├── .code-generation
└── config.js
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── pull_request_template.md
└── workflows
│ └── test.yaml
├── .gitignore
├── .htaccess
├── CHANGELOG.md
├── CONTRIBUTING.md
├── DEVELOPER_GUIDELINE.md
├── LICENSE
├── README.md
├── composer.json
├── docs
├── CloudinaryFilter.php
├── Makefile
├── sami_config.php
└── themes
│ └── cloudinary
│ ├── class.twig
│ ├── css
│ └── cloudinary.css
│ ├── index.twig
│ ├── layout
│ ├── base.twig
│ └── layout.twig
│ ├── macros.twig
│ ├── manifest.yml
│ └── sami.js.twig
├── phpcs.xml
├── phpstan.neon
├── phpunit.xml
├── samples
├── SamplePage
│ ├── Sample
│ │ ├── Sample.php
│ │ ├── Tabs
│ │ │ ├── BaseTab.php
│ │ │ ├── CodeTab.php
│ │ │ ├── TagTab.php
│ │ │ └── TransformationTab.php
│ │ ├── TagSample.php
│ │ └── TransformationSample.php
│ ├── SamplePage.php
│ └── SamplePageUtils.php
├── edit-me.php
├── styles.css
├── tag-samples.php
└── transformation-samples.php
├── src
├── Api
│ ├── Admin
│ │ ├── AdminApi.php
│ │ ├── AnalysisTrait.php
│ │ ├── ApiEndPoint.php
│ │ ├── AssetsTrait.php
│ │ ├── FoldersTrait.php
│ │ ├── MetadataFieldsTrait.php
│ │ ├── MiscTrait.php
│ │ ├── StreamingProfilesTrait.php
│ │ ├── TransformationsTrait.php
│ │ ├── UploadMappingsTrait.php
│ │ └── UploadPresetsTrait.php
│ ├── ApiClient.php
│ ├── ApiResponse.php
│ ├── BaseApiClient.php
│ ├── Exception
│ │ ├── AlreadyExists.php
│ │ ├── ApiError.php
│ │ ├── AuthorizationRequired.php
│ │ ├── BadRequest.php
│ │ ├── GeneralError.php
│ │ ├── NotAllowed.php
│ │ ├── NotFound.php
│ │ └── RateLimited.php
│ ├── Metadata
│ │ ├── DateMetadataField.php
│ │ ├── EnumMetadataField.php
│ │ ├── IntMetadataField.php
│ │ ├── Metadata.php
│ │ ├── MetadataDataEntry.php
│ │ ├── MetadataDataSource.php
│ │ ├── MetadataField.php
│ │ ├── MetadataFieldList.php
│ │ ├── MetadataFieldType.php
│ │ ├── SetMetadataField.php
│ │ ├── StringMetadataField.php
│ │ └── Validators
│ │ │ ├── AndValidator.php
│ │ │ ├── ComparisonRule.php
│ │ │ ├── DateGreaterThan.php
│ │ │ ├── DateLessThan.php
│ │ │ ├── IntGreaterThan.php
│ │ │ ├── IntLessThan.php
│ │ │ ├── MetadataValidation.php
│ │ │ └── StringLength.php
│ ├── Provisioning
│ │ ├── AccountApi.php
│ │ ├── AccountApiClient.php
│ │ ├── AccountEndPoint.php
│ │ └── UserRole.php
│ ├── Search
│ │ ├── SearchApi.php
│ │ ├── SearchFoldersApi.php
│ │ ├── SearchQueryInterface.php
│ │ └── SearchQueryTrait.php
│ ├── Upload
│ │ ├── ArchiveTrait.php
│ │ ├── ContextCommand.php
│ │ ├── ContextTrait.php
│ │ ├── CreativeTrait.php
│ │ ├── EditTrait.php
│ │ ├── TagCommand.php
│ │ ├── TagTrait.php
│ │ ├── UploadApi.php
│ │ ├── UploadEndPoint.php
│ │ └── UploadTrait.php
│ ├── UploadApiClient.php
│ └── Utils
│ │ ├── ApiUtils.php
│ │ ├── HttpMethod.php
│ │ └── HttpStatusCode.php
├── Asset
│ ├── AccessControl
│ │ ├── AccessControlRule.php
│ │ └── AccessType.php
│ ├── Analytics
│ │ └── Analytics.php
│ ├── AssetFinalizerTrait.php
│ ├── AssetInterface.php
│ ├── AssetQualifiers.php
│ ├── AuthToken.php
│ ├── BaseAsset.php
│ ├── BaseMediaAsset.php
│ ├── DeliveryTypeTrait.php
│ ├── Descriptor
│ │ ├── AssetDescriptor.php
│ │ ├── AssetDescriptorTrait.php
│ │ ├── AssetTransformation.php
│ │ ├── AssetType.php
│ │ └── DeliveryType.php
│ ├── File.php
│ ├── Image.php
│ ├── Media.php
│ ├── MediaAssetFinalizerTrait.php
│ ├── Moderation
│ │ ├── ModerationStatus.php
│ │ └── ModerationType.php
│ ├── SearchAsset.php
│ ├── SearchAssetTrait.php
│ └── Video.php
├── Cloudinary.php
├── Configuration
│ ├── ApiConfig.php
│ ├── AssetConfigTrait.php
│ ├── AuthTokenConfig.php
│ ├── BaseConfigSection.php
│ ├── CloudConfig.php
│ ├── CloudConfigTrait.php
│ ├── ConfigUtils.php
│ ├── ConfigurableInterface.php
│ ├── Configuration.php
│ ├── LoggingConfig.php
│ ├── Provisioning
│ │ ├── ProvisioningAccountConfig.php
│ │ ├── ProvisioningConfigUtils.php
│ │ └── ProvisioningConfiguration.php
│ ├── ResponsiveBreakpointsConfig.php
│ ├── TagConfig.php
│ ├── TagConfigTrait.php
│ ├── UrlConfig.php
│ └── UrlConfigTrait.php
├── Exception
│ ├── ConfigurationException.php
│ └── Error.php
├── HttpClient
│ └── HttpClient.php
├── Log
│ ├── Logger.php
│ ├── LoggerDecorator.php
│ ├── LoggerDecoratorTrait.php
│ ├── LoggerTrait.php
│ └── LoggersList.php
├── Tag
│ ├── Attribute
│ │ ├── AudioSourceType.php
│ │ ├── Media.php
│ │ ├── Sizes.php
│ │ ├── SourceType.php
│ │ ├── SrcSet.php
│ │ └── VideoSourceType.php
│ ├── BaseConfigurableApiTag.php
│ ├── BaseImageTag.php
│ ├── BaseTag.php
│ ├── ClientHintsMetaTag.php
│ ├── FormInputTag.php
│ ├── FormTag.php
│ ├── ImageTag.php
│ ├── ImageTagDeliveryTypeTrait.php
│ ├── JsConfigTag.php
│ ├── PictureSourceTag.php
│ ├── PictureTag.php
│ ├── SpriteTag.php
│ ├── Tag.php
│ ├── TagBuilder.php
│ ├── TagUtils.php
│ ├── UploadTag.php
│ ├── VideoSourceTag.php
│ ├── VideoTag.php
│ ├── VideoTagDeliveryTypeTrait.php
│ └── VideoThumbnailTag.php
└── Utils
│ ├── FileUtils.php
│ ├── SignatureVerifier.php
│ └── Utils.php
├── tests
├── CloudinaryTestCase.php
├── Helpers
│ ├── Addon.php
│ ├── Feature.php
│ ├── MockAccountApi.php
│ ├── MockAccountApiClient.php
│ ├── MockAdminApi.php
│ ├── MockAnalytics.php
│ ├── MockApiClient.php
│ ├── MockApiClientTrait.php
│ ├── MockApiTrait.php
│ ├── MockSearchApi.php
│ ├── MockSearchFoldersApi.php
│ ├── MockUploadApi.php
│ ├── MockUploadApiClient.php
│ └── RequestAssertionsTrait.php
├── Integration
│ ├── Admin
│ │ ├── AdaptiveStreamingProfilesTest.php
│ │ ├── AssetTest.php
│ │ ├── Assets
│ │ │ ├── AssetsMetadataTest.php
│ │ │ ├── DeleteAssetsTest.php
│ │ │ ├── ListAssetsTest.php
│ │ │ └── RestoreAssetsTest.php
│ │ ├── FoldersTest.php
│ │ ├── MetadataFieldsTest.php
│ │ ├── MiscTest.php
│ │ ├── OAuthTest.php
│ │ ├── TagsTest.php
│ │ ├── TransformationsTest.php
│ │ ├── UploadMappingsTest.php
│ │ ├── UploadPresetsTest.php
│ │ └── UsageTest.php
│ ├── IntegrationTestCase.php
│ ├── Provisioning
│ │ ├── ProvisioningAccountTest.php
│ │ ├── ProvisioningIntegrationTestCase.php
│ │ ├── ProvisioningSubAccountTest.php
│ │ └── ProvisioningUserGroupTest.php
│ ├── Search
│ │ └── SearchApiTest.php
│ └── Upload
│ │ ├── ArchiveTest.php
│ │ ├── ContextTest.php
│ │ ├── CreativeTest.php
│ │ ├── EditTest.php
│ │ ├── TagTest.php
│ │ └── UploadApiTest.php
├── Unit
│ ├── Admin
│ │ ├── AdminApiTest.php
│ │ ├── AnalysisTest.php
│ │ ├── AssetsTest.php
│ │ ├── FoldersTest.php
│ │ ├── MetadataFieldsTest.php
│ │ └── OAuthTest.php
│ ├── ApiClientTest.php
│ ├── Archive
│ │ └── ArchiveTest.php
│ ├── Asset
│ │ ├── AnalyticsTest.php
│ │ ├── AssetAuthTokenTest.php
│ │ ├── AssetTestCase.php
│ │ ├── AssetTransformationTest.php
│ │ ├── AuthTokenTest.php
│ │ ├── AuthTokenTestCase.php
│ │ ├── DistributionTest.php
│ │ ├── FileTest.php
│ │ ├── ImageTest.php
│ │ ├── MediaFromParamsTest.php
│ │ ├── MediaTest.php
│ │ ├── SearchAssetTest.php
│ │ └── VideoTest.php
│ ├── Cloudinary
│ │ ├── CloudinaryAssetTest.php
│ │ ├── CloudinaryTagTest.php
│ │ └── CloudinaryTest.php
│ ├── Configuration
│ │ ├── CloudConfigTest.php
│ │ ├── ConfigUtilsTest.php
│ │ ├── ConfigurationTest.php
│ │ ├── Provisioning
│ │ │ └── ConfigurationAccountTest.php
│ │ └── SensitiveKeysSerializationTest.php
│ ├── HttpClientTest.php
│ ├── Logger
│ │ └── LoggerTest.php
│ ├── Provisioning
│ │ ├── AccessKeysTest.php
│ │ └── ProvisioningUnitTestCase.php
│ ├── Search
│ │ └── SearchApiTest.php
│ ├── Tag
│ │ ├── ClientHintsMetaTagTest.php
│ │ ├── FormInputTagTest.php
│ │ ├── FormTagTest.php
│ │ ├── ImageTagTest.php
│ │ ├── ImageTagTestCase.php
│ │ ├── JsConfigTagTest.php
│ │ ├── Patterns
│ │ │ └── FormTagPatterns.php
│ │ ├── PictureSourceTagTest.php
│ │ ├── PictureTagTest.php
│ │ ├── Responsive
│ │ │ ├── GetBreakpointsTest.php
│ │ │ └── SrcSetAttributeTest.php
│ │ ├── SpriteTagTest.php
│ │ ├── TagFromParamsTest.php
│ │ ├── TagTest.php
│ │ ├── TagTestCase.php
│ │ ├── TestTag.php
│ │ ├── UploadTagTest.php
│ │ ├── VideoTagTest.php
│ │ └── VideoThumbnailTagTest.php
│ ├── TestHelpers
│ │ ├── TestClassA.php
│ │ ├── TestClassB.php
│ │ └── TestLogger.php
│ ├── UnitTestCase.php
│ ├── Upload
│ │ ├── CreateSlideshowTest.php
│ │ ├── OAuthTest.php
│ │ └── UploadApiTest.php
│ └── Utils
│ │ ├── ApiUtilsTest.php
│ │ ├── FileUtilsTest.php
│ │ ├── SignatureVerifierTest.php
│ │ └── UtilsTest.php
└── assets
│ ├── sample.docx
│ ├── sample.gif
│ ├── sample.ico
│ ├── sample.mp4
│ └── sample.png
└── tools
├── allocate_test_cloud.sh
├── get_test_cloud.sh
└── update_version.sh
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Bug report for Cloudinary PHP SDK
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Bug report for Cloudinary PHP SDK
11 | Before proceeding, please update to latest version and test if the issue persists
12 |
13 | ## Describe the bug in a sentence or two.
14 | …
15 |
16 | ## Issue Type (Can be multiple)
17 | - [ ] Build - Can’t install or import the SDK
18 | - [ ] Performance - Performance issues
19 | - [ ] Behaviour - Functions aren’t working as expected (such as generate URL)
20 | - [ ] Documentation - Inconsistency between the docs and behaviour
21 | - [ ] Other (Specify)
22 |
23 | ## Steps to reproduce
24 | … if applicable
25 |
26 | ## Error screenshots or Stack Trace (if applicable)
27 | …
28 |
29 | ## Operating System
30 | - [ ] Linux
31 | - [ ] Windows
32 | - [ ] macOS
33 | - [ ] All
34 |
35 | ## Environment and Frameworks (fill in the version numbers)
36 |
37 | - PHP Cloudinary SDK version - 0.0.0
38 | - PHP Version - 0.0.0
39 | - Framework (Laravel, Symphony, etc) - 0.0.0
40 |
41 | ## Repository
42 |
43 | If possible, please provide a link to a reproducible repository that showcases the problem
44 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Feature request for Cloudinary PHP SDK
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Feature request for Cloudinary PHP SDK
11 | …(If your feature is for other SDKs, please request them there)
12 |
13 |
14 | ## Explain your use case
15 | … (A high level explanation of why you need this feature)
16 |
17 | ## Describe the problem you’re trying to solve
18 | … (A more technical view of what you’d like to accomplish, and how this feature will help you achieve it)
19 |
20 | ## Do you have a proposed solution?
21 | … (yes, no? Please elaborate if needed)
22 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ### Brief Summary of Changes
2 |
3 |
4 | #### What does this PR address?
5 | - [ ] GitHub issue (Add reference - #XX)
6 | - [ ] Refactoring
7 | - [ ] New feature
8 | - [ ] Bug fix
9 | - [ ] Adds more tests
10 |
11 | #### Are tests included?
12 | - [ ] Yes
13 | - [ ] No
14 |
15 | #### Reviewer, please note:
16 |
23 |
24 | #### Checklist:
25 |
26 |
27 | - [ ] My code follows the code style of this project.
28 | - [ ] My change requires a change to the documentation.
29 | - [ ] I ran the full test suite before pushing the changes and all of the tests pass.
30 |
--------------------------------------------------------------------------------
/.github/workflows/test.yaml:
--------------------------------------------------------------------------------
1 | name: Tests
2 | on: [push, pull_request]
3 | jobs:
4 | php:
5 | name: PHP ${{ matrix.php-versions }}
6 | runs-on: ubuntu-latest
7 | strategy:
8 | fail-fast: false
9 | matrix:
10 | php-versions:
11 | - '8.0'
12 | - '8.1'
13 | - '8.2'
14 | - '8.3'
15 | - '8.4'
16 | steps:
17 | - name: Checkout
18 | uses: actions/checkout@v4
19 | - name: Setup PHP, with composer and extensions
20 | uses: shivammathur/setup-php@v2
21 | with:
22 | php-version: ${{ matrix.php-versions }}
23 | extensions: json
24 | coverage: xdebug
25 | - name: Install Composer dependencies
26 | run: composer update -n
27 | - name: Run Tests
28 | run: |
29 | export CLOUDINARY_URL=$(bash tools/get_test_cloud.sh);
30 | echo cloud_name: "$(echo $CLOUDINARY_URL | cut -d'@' -f2)"
31 | vendor/bin/simple-phpunit
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | composer.lock
3 | tests/coverage
4 | output/
5 | .idea
6 | composer.phar
7 | docs/sami.phar
8 | docs/cache/
9 | docs/build/
10 | tools/dev/sanity/node_modules
11 | tools/dev/sanity/package-lock.json
12 | tools/dev/sanity/results.json
13 | tools/dev/sanity/TransformationSanityTest.php
14 | /.phpunit.result.cache
15 |
--------------------------------------------------------------------------------
/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | deny from all
3 |
4 |
--------------------------------------------------------------------------------
/DEVELOPER_GUIDELINE.md:
--------------------------------------------------------------------------------
1 | # Developing Cloudinary PHP
2 |
3 | ## Code style
4 |
5 | ### Recommended Standards
6 | All code should follow the following standards:
7 | - [PSR-1](http://www.php-fig.org/psr/psr-1/)
8 | - [PSR-2](http://www.php-fig.org/psr/psr-2/)
9 | - [PSR-3 _Recommended_](http://www.php-fig.org/psr/psr-3/)
10 | - [PSR-5 _Recommended_](https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md)
11 | - [PSR-12](https://www.php-fig.org/psr/psr-12/)
12 |
13 | ### PHP Code Size Control
14 | All code should meet default configuration of [PHPMD](https://phpmd.org/rules/codesize.html)
15 |
16 | ## Tests Coverage
17 | All code must be covered by tests using [PHPUnit](https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html)
18 | For functional tests unique IDs should be used and after test is done all data from remote server should be removed.
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Cloudinary
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 all
13 | 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 THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloudinary/cloudinary_php",
3 | "version": "3.1.0",
4 | "description": "Cloudinary PHP SDK",
5 | "keywords": [
6 | "cloudinary",
7 | "sdk",
8 | "cloud",
9 | "image management",
10 | "cdn"
11 | ],
12 | "type": "library",
13 | "homepage": "https://github.com/cloudinary/cloudinary_php",
14 | "minimum-stability": "stable",
15 | "license": "MIT",
16 | "authors": [
17 | {
18 | "name": "Cloudinary",
19 | "homepage": "https://github.com/cloudinary/cloudinary_php/graphs/contributors"
20 | }
21 | ],
22 | "support": {
23 | "email": "info@cloudinary.com",
24 | "issues": "https://github.com/cloudinary/cloudinary_php/issues"
25 | },
26 | "require": {
27 | "php": ">=8.0.0",
28 | "cloudinary/transformation-builder-sdk": "^2",
29 | "guzzlehttp/guzzle": "^7.4.5",
30 | "guzzlehttp/promises": "^1.5.3|^2.0",
31 | "guzzlehttp/psr7": "^2.7",
32 | "ext-json": "*",
33 | "monolog/monolog": "^2|^3",
34 | "psr/log" : "^2|^3"
35 | },
36 | "require-dev": {
37 | "symfony/phpunit-bridge": "^7.2",
38 | "phpmd/phpmd": "*",
39 | "squizlabs/php_codesniffer": "*",
40 | "friendsofphp/php-cs-fixer": "*",
41 | "ext-dom": "*",
42 | "ext-libxml": "*",
43 | "ext-zip": "*"
44 | },
45 | "autoload": {
46 | "classmap": [
47 | "src"
48 | ]
49 | },
50 | "autoload-dev": {
51 | "psr-4": {
52 | "Cloudinary\\Test\\": "tests"
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/docs/CloudinaryFilter.php:
--------------------------------------------------------------------------------
1 | getTags(self::API);
35 | }
36 |
37 | /**
38 | * Accept only public methods that are not tagged '@internal'.
39 | *
40 | * @param MethodReflection $method The method reflection object.
41 | *
42 | * @return bool
43 | */
44 | public function acceptMethod(MethodReflection $method)
45 | {
46 | return $method->isPublic() && ! $method->getTags(self::INTERNAL);
47 | }
48 |
49 | /**
50 | * Accept only public properties that are not tagged '@internal'.
51 | *
52 | * @param PropertyReflection $property The property reflection object.
53 | *
54 | * @return bool
55 | */
56 | public function acceptProperty(PropertyReflection $property)
57 | {
58 | return $property->isPublic() && ! $property->getTags(self::INTERNAL);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | CACHE_DIR = cache
2 | BUILD_DIR = build
3 |
4 | DOCS_TOOL = sami.phar
5 |
6 | PHP?=php
7 |
8 | CONFIG=sami_config.php
9 |
10 | .PHONY: all clean update
11 |
12 | all: update
13 |
14 | update: $(DOCS_TOOL)
15 | $(PHP) $(DOCS_TOOL) update $(CONFIG)
16 |
17 | $(DOCS_TOOL):
18 | curl -O https://cloudinary-res.cloudinary.com/raw/upload/docsite/sami.phar
19 |
20 | clean:
21 | @rm -rf $(CACHE_DIR) $(BUILD_DIR)
22 |
--------------------------------------------------------------------------------
/docs/sami_config.php:
--------------------------------------------------------------------------------
1 | 'cloudinary',
15 | 'template_dirs' => [$docsDir . 'themes'],
16 | 'title' => 'Cloudinary PHP SDK',
17 | 'version' => '3.1.0',
18 | 'build_dir' => $docsDir . 'build',
19 | 'cache_dir' => $docsDir . 'cache',
20 | 'default_opened_level' => 1,
21 | 'filter' => new CloudinaryFilter(),
22 | ]
23 | );
24 |
--------------------------------------------------------------------------------
/docs/themes/cloudinary/index.twig:
--------------------------------------------------------------------------------
1 | {% extends "layout/layout.twig" %}
2 |
3 | {% block body_class 'index' %}
4 |
5 | {% block page_content %}
6 |
9 |
10 |
This reference provides details on all PHP SDK asset management namespaces and classes.
11 |
For details on the PHP SDK transformation namespaces and classes,
12 | see the PHP SDK Transformation Reference.
13 |
14 |
17 | {% if namespaces %}
18 |
19 | {% set last_name = '' %}
20 | {% for namespace in namespaces %}
21 | {% set top_level = namespace|split('\\')|first %}
22 | {% if top_level != last_name %}
23 | {% if last_name %}
{% endif %}
24 |
25 |
{{ top_level|raw }}
26 |
27 | {% set last_name = top_level %}
28 | {% endif %}
29 | - {{ namespace|raw }}
30 | {% endfor %}
31 |
32 |
33 |
34 | {% endif %}
35 |
36 | {% endblock %}
37 |
38 |
39 |
--------------------------------------------------------------------------------
/docs/themes/cloudinary/layout/base.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {% block title project.config('title') %}
7 |
8 | {% block head %}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | {% endblock %}
21 |
22 |
23 |
24 | {% if project.config('base_url') %}
25 | {%- for version in project.versions -%}
26 |
30 | {% endfor -%}
31 | {% endif %}
32 |
33 |
34 | {% block html %}
35 |
36 | {% block content '' %}
37 |
38 | {% endblock %}
39 |
40 |
41 |
--------------------------------------------------------------------------------
/docs/themes/cloudinary/manifest.yml:
--------------------------------------------------------------------------------
1 | name: cloudinary
2 | parent: default
3 | static:
4 | 'css/cloudinary.css': 'css/cloudinary.css'
5 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | cloudinary_php coding standard
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | src
20 | tests
21 |
22 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 1
3 | paths:
4 | - src
5 | ignoreErrors:
6 | - '#Unsafe usage of new static\(\)#'
7 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ./src
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | tests/Unit
15 |
16 |
17 | tests/Integration
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/samples/SamplePage/Sample/Tabs/BaseTab.php:
--------------------------------------------------------------------------------
1 | title = $title;
30 | $this->text = $text;
31 | }
32 |
33 | public function getTabPill()
34 | {
35 | $class = 'url-tab nav-link';
36 | if ($this->isFirst) {
37 | $class .= ' active';
38 | }
39 | return '
40 |
41 | ' .
46 | strtoupper($this->title) .
47 | '
48 |
49 | ';
50 | }
51 |
52 | public function getTabContent()
53 | {
54 | return '';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/samples/SamplePage/Sample/Tabs/CodeTab.php:
--------------------------------------------------------------------------------
1 | text = $code;
39 | $this->isFirst = true;
40 | $this->keepSpaces = $keepSpaces;
41 | }
42 |
43 | public function getTabContent()
44 | {
45 | return '
46 |
47 |
51 | ' . getColoredPhp($this->text, $this->keepSpaces) . '
52 |
53 | ';
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/samples/SamplePage/Sample/Tabs/TagTab.php:
--------------------------------------------------------------------------------
1 | html = $html;
37 | }
38 |
39 | public function getTabContent()
40 | {
41 | // TODO: add getFormattedHtml() function to SamplePageUtils
42 |
43 | return '
44 |
' .
49 | getFormattedHtml($this->html) .
50 | '
51 |
52 | ';
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/samples/SamplePage/Sample/Tabs/TransformationTab.php:
--------------------------------------------------------------------------------
1 | transformation = $transformation;
51 | $this->publicId = $publicId;
52 | $this->text = $code;
53 | $this->type = $type;
54 | }
55 |
56 | public function getTabContent()
57 | {
58 | $url = $this->calculateUrl();
59 | return '
60 |
72 |
73 | ';
74 | }
75 |
76 | private function calculateUrl()
77 | {
78 | $tag = $this->type === 'video' ? Video::upload($this->publicId) : Image::upload($this->publicId);
79 | return $tag->toUrl($this->transformation);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/samples/SamplePage/Sample/TagSample.php:
--------------------------------------------------------------------------------
1 | tag = $tag;
40 | }
41 |
42 | /**
43 | * @return array
44 | */
45 | protected function createTabs()
46 | {
47 | return [
48 | $this->createCodeTab(),
49 | new TagTab(
50 | $this->code,
51 | $this->tag
52 | )
53 | ];
54 | }
55 |
56 | protected function getExample()
57 | {
58 | return $this->getExampleHtml($this->getUrl(), $this->tag);
59 | }
60 |
61 | protected function getUrl()
62 | {
63 | // TODO: return actual url from tag
64 | return 'http://cloudinary.com';
65 | }
66 |
67 | /**
68 | * @param string $url
69 | * @param BaseTag $tag
70 | *
71 | * @return string
72 | */
73 | protected function getExampleHtml($url = '', $tag = null)
74 | {
75 | return '
76 | ' .
77 | $tag->addClass('z - depth - 1')->setAttribute('style', 'margin:auto; max-width: 900px;') . '
78 |
79 |
80 | ';
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Api/Admin/AdminApi.php:
--------------------------------------------------------------------------------
1 |
21 | * Admin API Reference
22 | *
23 | * @api
24 | */
25 | class AdminApi
26 | {
27 | use AssetsTrait;
28 | use FoldersTrait;
29 | use TransformationsTrait;
30 | use StreamingProfilesTrait;
31 | use UploadPresetsTrait;
32 | use UploadMappingsTrait;
33 | use MiscTrait;
34 | use MetadataFieldsTrait;
35 | use AnalysisTrait;
36 |
37 | /**
38 | * @var ApiClient $apiClient The API client instance.
39 | */
40 | protected $apiClient;
41 |
42 | /**
43 | * @var ApiClient $apiV2Client The API v2 client instance.
44 | */
45 | protected $apiV2Client;
46 |
47 | /**
48 | * AdminApi constructor.
49 | *
50 | * @param mixed|null $configuration
51 | *
52 | * @noinspection UnusedConstructorDependenciesInspection*/
53 | public function __construct(mixed $configuration = null)
54 | {
55 | $this->apiClient = new ApiClient($configuration);
56 |
57 | $apiV2Configuration = new Configuration($configuration);
58 | $apiV2Configuration->api->apiVersion = '2';
59 |
60 | $this->apiV2Client = new ApiClient($apiV2Configuration);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Api/Admin/AnalysisTrait.php:
--------------------------------------------------------------------------------
1 | analyzeAsync($inputType, $analysisType, $uri, $parameters)->wait();
47 | }
48 |
49 | /**
50 | * Analyzes an asset with the requested analysis type asynchronously.
51 | *
52 | * @param string $inputType The type of input for the asset to analyze ('uri').
53 | * @param string $analysisType The type of analysis to run ('google_tagging', 'captioning', 'fashion').
54 | * @param string|null $uri The URI of the asset to analyze.
55 | * @param array|null $parameters Additional parameters.
56 | *
57 | * @see https://cloudinary.com/documentation/media_analyzer_api_reference
58 | */
59 | public function analyzeAsync(
60 | string $inputType,
61 | string $analysisType,
62 | ?string $uri = null,
63 | ?array $parameters = null
64 | ): PromiseInterface {
65 | $endPoint = [ApiEndPoint::ANALYSIS, 'analyze', $inputType];
66 |
67 | $params = ['analysis_type' => $analysisType, 'uri' => $uri, 'parameters' => $parameters];
68 |
69 | return $this->apiV2Client->postJsonAsync($endPoint, $params);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Api/Admin/ApiEndPoint.php:
--------------------------------------------------------------------------------
1 | headers = $headers;
58 | // According to RFC 2616, header names are case-insensitive.
59 | $lcHeaders = array_change_key_case($headers);
60 |
61 | $this->rateLimitResetAt = strtotime(ArrayUtils::get($lcHeaders, ['x-featureratelimit-reset', 0], 0));
62 | $this->rateLimitAllowed = (int)ArrayUtils::get($lcHeaders, ['x-featureratelimit-limit', 0], 0);
63 | $this->rateLimitRemaining = (int)ArrayUtils::get($lcHeaders, ['x-featureratelimit-remaining', 0], 0);
64 |
65 | parent::__construct($responseJson);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Api/Exception/AlreadyExists.php:
--------------------------------------------------------------------------------
1 | type = MetadataFieldType::DATE;
32 | }
33 |
34 | /**
35 | * Sets the default date for this field.
36 | *
37 | * @param mixed $defaultValue The date to set.
38 | */
39 | public function setDefaultValue(mixed $defaultValue): void
40 | {
41 | $this->defaultValue = Utils::toISO8601DateOnly($defaultValue);
42 | }
43 |
44 | /**
45 | * Gets the default date of this field.
46 | *
47 | * @throws Exception When the underlying value is malformed.
48 | */
49 | public function getDefaultValue(): ?DateTime
50 | {
51 | return $this->defaultValue ? new DateTime($this->defaultValue) : null;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Api/Metadata/EnumMetadataField.php:
--------------------------------------------------------------------------------
1 | type = MetadataFieldType::ENUM;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Api/Metadata/IntMetadataField.php:
--------------------------------------------------------------------------------
1 | type = MetadataFieldType::INTEGER;
28 | }
29 |
30 | /**
31 | * Sets the default value for this field.
32 | *
33 | */
34 | public function setDefaultValue(mixed $defaultValue): void
35 | {
36 | $this->defaultValue = (int)$defaultValue;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Api/Metadata/Metadata.php:
--------------------------------------------------------------------------------
1 | getPropertyKeys();
39 |
40 | $snakeCaseProperties = [];
41 | foreach ($propertyKeys as $key) {
42 | $value = $this->{$key} ?? null;
43 | if ($value === null) {
44 | continue;
45 | }
46 | if (is_object($value)) {
47 | if (method_exists($value, 'jsonSerialize')) {
48 | $snakeCaseProperties[StringUtils::camelCaseToSnakeCase($key)] = $value->jsonSerialize();
49 | }
50 | } elseif (is_array($value) && !ArrayUtils::isAssoc($value)) {
51 | $subArray = [];
52 | foreach ($value as $subArrayValue) {
53 | if (method_exists($subArrayValue, 'jsonSerialize')) {
54 | $subArray[] = $subArrayValue->jsonSerialize();
55 | } else {
56 | $subArray[] = $subArrayValue;
57 | }
58 | }
59 | $snakeCaseProperties[StringUtils::camelCaseToSnakeCase($key)] = $subArray;
60 | } else {
61 | $snakeCaseProperties[StringUtils::camelCaseToSnakeCase($key)] = $value;
62 | }
63 | }
64 |
65 | return $snakeCaseProperties;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Api/Metadata/MetadataDataEntry.php:
--------------------------------------------------------------------------------
1 | setValue($value);
33 | $this->setExternalId($externalId);
34 | }
35 |
36 | /**
37 | * Gets the keys for all the properties of this object.
38 | *
39 | */
40 | public function getPropertyKeys(): array
41 | {
42 | return ['externalId', 'value'];
43 | }
44 |
45 | /**
46 | * Gets the value of the entry.
47 | *
48 | */
49 | public function getValue(): string
50 | {
51 | return $this->value;
52 | }
53 |
54 | /**
55 | * Sets the value of the entry.
56 | *
57 | */
58 | public function setValue(string $value): void
59 | {
60 | if (is_null($value)) {
61 | throw new InvalidArgumentException('Metadata data entry value is not valid');
62 | }
63 | $this->value = $value;
64 | }
65 |
66 | /**
67 | * Gets the ID of the entry.
68 | *
69 | */
70 | public function getExternalId(): string
71 | {
72 | return $this->externalId;
73 | }
74 |
75 | /**
76 | * Sets the ID of the entry. Will be auto-generated if left blank.
77 | *
78 | * @param ?string $externalId The external ID.
79 | */
80 | public function setExternalId(?string $externalId): void
81 | {
82 | $this->externalId = $externalId;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/Api/Metadata/MetadataDataSource.php:
--------------------------------------------------------------------------------
1 | setValues($values);
37 | }
38 |
39 | /**
40 | * Gets the keys for all the properties of this object.
41 | *
42 | */
43 | public function getPropertyKeys(): array
44 | {
45 | return ['values'];
46 | }
47 |
48 | /**
49 | * Sets entities for this data source.
50 | *
51 | * @param MetadataDataEntry[]|array[] $values
52 | *
53 | * @throws InvalidArgumentException
54 | */
55 | public function setValues(array $values): void
56 | {
57 | $this->values = [];
58 | foreach ($values as $value) {
59 | if ($value instanceof MetadataDataEntry) {
60 | $this->values[] = $value;
61 | } elseif (is_array($value) && isset($value['value'])) {
62 | $this->values[] = new MetadataDataEntry(
63 | $value['value'],
64 | $value['external_id'] ?? null
65 | );
66 | } else {
67 | throw new InvalidArgumentException('The specified metadata datasource values are not valid.');
68 | }
69 | }
70 | }
71 |
72 | /**
73 | * Gets entities of this data source.
74 | *
75 | * @return MetadataDataEntry[]
76 | */
77 | public function getValues(): array
78 | {
79 | return $this->values;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/Api/Metadata/MetadataFieldType.php:
--------------------------------------------------------------------------------
1 | type = MetadataFieldType::SET;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Api/Metadata/StringMetadataField.php:
--------------------------------------------------------------------------------
1 | type = MetadataFieldType::STRING;
27 | }
28 |
29 | /**
30 | * Sets the default value.
31 | *
32 | */
33 | public function setDefaultValue(mixed $defaultValue): void
34 | {
35 | $this->defaultValue = (string)$defaultValue;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Api/Metadata/Validators/AndValidator.php:
--------------------------------------------------------------------------------
1 | type = self::RULE_AND;
35 | $this->rules = $rules;
36 | }
37 |
38 | /**
39 | * Gets the keys for all the properties of this object.
40 | *
41 | * @return string[]
42 | */
43 | public function getPropertyKeys(): array
44 | {
45 | return array_merge(parent::getPropertyKeys(), ['rules']);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Api/Metadata/Validators/ComparisonRule.php:
--------------------------------------------------------------------------------
1 | type = $type;
30 | $this->setValue($value);
31 | $this->equals = $equals;
32 | }
33 |
34 | protected function setValue(mixed $value): void
35 | {
36 | $this->value = $value;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Api/Metadata/Validators/DateGreaterThan.php:
--------------------------------------------------------------------------------
1 | value = Utils::toISO8601DateOnly($value);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Api/Metadata/Validators/DateLessThan.php:
--------------------------------------------------------------------------------
1 | value = Utils::toISO8601DateOnly($value);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Api/Metadata/Validators/IntGreaterThan.php:
--------------------------------------------------------------------------------
1 | type = self::STRLEN;
31 | $this->min = $min;
32 | $this->max = $max;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Api/Provisioning/AccountEndPoint.php:
--------------------------------------------------------------------------------
1 | endpoint(self::FOLDERS);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Api/Search/SearchQueryInterface.php:
--------------------------------------------------------------------------------
1 | accessType = $accessType;
60 | $this->start = $start;
61 | $this->end = $end;
62 | }
63 |
64 |
65 | /**
66 | * Serializes to JSON
67 | */
68 | public function jsonSerialize(): array
69 | {
70 | return ArrayUtils::safeFilter(
71 | [
72 | 'access_type' => $this->accessType,
73 | 'start' => Utils::formatDate($this->start),
74 | 'end' => Utils::formatDate($this->end),
75 | ]
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Asset/AccessControl/AccessType.php:
--------------------------------------------------------------------------------
1 | [DeliveryType::UPLOAD => 'files'],
30 | ];
31 | }
32 |
--------------------------------------------------------------------------------
/src/Asset/Image.php:
--------------------------------------------------------------------------------
1 | [
34 | DeliveryType::UPLOAD => 'images',
35 | DeliveryType::PRIVATE_DELIVERY => 'private_images',
36 | DeliveryType::AUTHENTICATED => 'authenticated_images',
37 | ],
38 | ];
39 |
40 | /**
41 | * Gets the transformation.
42 | *
43 | */
44 | public function getTransformation(): CommonTransformation
45 | {
46 | if (! isset($this->transformation)) {
47 | $this->transformation = new ImageTransformation();
48 | }
49 |
50 | return $this->transformation;
51 | }
52 |
53 | /**
54 | * Finalizes the asset type.
55 | *
56 | */
57 | protected function finalizeAssetType(): ?string
58 | {
59 | return $this->finalizeShorten(parent::finalizeAssetType());
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Asset/Media.php:
--------------------------------------------------------------------------------
1 | transformation)) {
52 | $this->transformation = new Transformation();
53 | }
54 |
55 | return $this->transformation;
56 | }
57 |
58 | /**
59 | * Internal getter for a list of the delivery types that support SEO suffix.
60 | *
61 | *
62 | * @internal
63 | */
64 | public static function getSuffixSupportedDeliveryTypes(): array
65 | {
66 | if (empty(self::$suffixSupportedDeliveryTypes)) {
67 | self::$suffixSupportedDeliveryTypes = ArrayUtils::mergeNonEmpty(
68 | Image::getSuffixSupportedDeliveryTypes(),
69 | Video::getSuffixSupportedDeliveryTypes(),
70 | File::getSuffixSupportedDeliveryTypes()
71 | );
72 | }
73 |
74 | return self::$suffixSupportedDeliveryTypes;
75 | }
76 |
77 | /**
78 | * Finalizes the asset type.
79 | *
80 | */
81 | protected function finalizeAssetType(): ?string
82 | {
83 | return $this->finalizeShorten(parent::finalizeAssetType());
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/Asset/Moderation/ModerationStatus.php:
--------------------------------------------------------------------------------
1 | ttl = $ttl;
24 |
25 | return $this;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Asset/Video.php:
--------------------------------------------------------------------------------
1 | [DeliveryType::UPLOAD => 'videos'],
32 | ];
33 |
34 | /**
35 | * Gets the transformation.
36 | *
37 | */
38 | public function getTransformation(): CommonTransformation|VideoTransformation
39 | {
40 | if (! isset($this->transformation)) {
41 | $this->transformation = new VideoTransformation();
42 | }
43 |
44 | return $this->transformation;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Configuration/AssetConfigTrait.php:
--------------------------------------------------------------------------------
1 | Delivering token based authenticated media assets
16 | *
17 | * @api
18 | */
19 | class AuthTokenConfig extends BaseConfigSection
20 | {
21 | public const CONFIG_NAME = 'auth_token';
22 |
23 | // Supported parameters
24 | public const KEY = 'key';
25 | public const IP = 'ip';
26 | public const ACL = 'acl';
27 | public const START_TIME = 'start_time';
28 | public const EXPIRATION = 'expiration';
29 | public const DURATION = 'duration';
30 |
31 | /**
32 | * (Required) – the token must be signed with the encryption key received from Cloudinary.
33 | *
34 | * @var ?string
35 | */
36 | public ?string $key = null;
37 |
38 | /**
39 | * (Optional) – only this IP address can access the resource.
40 | *
41 | * @var ?string
42 | */
43 | public ?string $ip = null;
44 |
45 | /**
46 | * (Optional) – an Access Control List for limiting the allowed URL path to a specified pattern (e.g.,
47 | * /video/authenticated/*).
48 | *
49 | * The pattern can include any of Cloudinary's transformations to also apply to the
50 | * delivered assets. Note that if you add an overlay (e.g., for a watermark), you should also include the
51 | * fl_layer_apply flag to ensure the layer cannot be modified. This parameter is useful for generating a token
52 | * that can be added to a number of different URLs that share a common transformation. Without this parameter,
53 | * the pattern defaults to the full URL path of the requested asset.
54 | *
55 | * @var string|array|null
56 | */
57 | public string|array|null $acl = null;
58 |
59 | /**
60 | * (Optional) – timestamp of the UNIX time when the URL becomes valid. Default value: the current time.
61 | *
62 | * @var ?int
63 | */
64 | public ?int $startTime = null;
65 |
66 | /**
67 | * (Optional) – timestamp of the UNIX time when the URL expires.
68 | *
69 | * @var ?int
70 | */
71 | public ?int $expiration = null;
72 |
73 | /**
74 | * (Optional) – the duration that the URL is valid in seconds (counted from start_time).
75 | *
76 | * @var ?int
77 | */
78 | public ?int $duration = null;
79 | }
80 |
--------------------------------------------------------------------------------
/src/Configuration/CloudConfigTrait.php:
--------------------------------------------------------------------------------
1 | setCloudConfig(CloudConfig::CLOUD_NAME, $cloudName);
32 | }
33 |
34 | /**
35 | * Sets the OAuth2.0 token.
36 | *
37 | * @param ?string $oauthToken Used instead of API key and API secret
38 | *
39 | * @return $this
40 | *
41 | * @api
42 | */
43 | public function oauthToken(?string $oauthToken): static
44 | {
45 | return $this->setCloudConfig(CloudConfig::OAUTH_TOKEN, $oauthToken);
46 | }
47 |
48 | /**
49 | * Sets the signature algorithm.
50 | *
51 | * @param string $signatureAlgorithm The algorithm to use. (Can be SHA1 or SHA256).
52 | *
53 | * @return $this
54 | *
55 | * @api
56 | */
57 | public function signatureAlgorithm(string $signatureAlgorithm): static
58 | {
59 | return $this->setCloudConfig(CloudConfig::SIGNATURE_ALGORITHM, $signatureAlgorithm);
60 | }
61 |
62 | /**
63 | * Sets the Cloud configuration key with the specified value.
64 | *
65 | * @param string $configKey The configuration key.
66 | * @param mixed $configValue THe configuration value.
67 | *
68 | * @return $this
69 | *
70 | * @internal
71 | */
72 | abstract public function setCloudConfig(string $configKey, mixed $configValue): static;
73 | }
74 |
--------------------------------------------------------------------------------
/src/Configuration/ConfigurableInterface.php:
--------------------------------------------------------------------------------
1 | :@]" expected'
63 | );
64 | }
65 |
66 | $config = [ProvisioningAccountConfig::ACCOUNT_ID => $uri->getHost()];
67 |
68 | $userPass = explode(':', $uri->getUserInfo(), 2);
69 |
70 | ArrayUtils::addNonEmpty(
71 | $config,
72 | ProvisioningAccountConfig::PROVISIONING_API_KEY,
73 | ArrayUtils::get($userPass, 0)
74 | );
75 | ArrayUtils::addNonEmpty(
76 | $config,
77 | ProvisioningAccountConfig::PROVISIONING_API_SECRET,
78 | ArrayUtils::get($userPass, 1)
79 | );
80 |
81 | return [ProvisioningAccountConfig::CONFIG_NAME => $config];
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Configuration/ResponsiveBreakpointsConfig.php:
--------------------------------------------------------------------------------
1 | Responsive breakpoints
17 | *
18 | * @property ?int $minWidth The minimum width needed for the image. Default: 375.
19 | * @property ?int $maxWidth The maximum width needed for the image. Default 3840.
20 | * @property ?int $maxImages The maximal number of breakpoints.
21 | *
22 | * @api
23 | */
24 | class ResponsiveBreakpointsConfig extends BaseConfigSection
25 | {
26 | public const CONFIG_NAME = 'responsive_breakpoints';
27 |
28 | public const DEFAULT_MIN_WIDTH = 375;
29 | public const DEFAULT_MAX_WIDTH = 3840;
30 | public const DEFAULT_MAX_IMAGES = 5;
31 |
32 | // Supported parameters
33 | public const BREAKPOINTS = 'breakpoints';
34 |
35 | public const MIN_WIDTH = 'min_width';
36 | public const MAX_WIDTH = 'max_width';
37 | public const MAX_IMAGES = 'max_images';
38 |
39 | public const AUTO_OPTIMAL_BREAKPOINTS = 'auto_optimal_breakpoints';
40 |
41 | /**
42 | * An array of static breakpoints to use (overrides Cloudinary-optimized breakpoints).
43 | *
44 | * @var array|null
45 | */
46 | public ?array $breakpoints = null;
47 |
48 | /**
49 | * The minimum width needed for the image. Default: 375.
50 | *
51 | * @var ?int
52 | */
53 | protected ?int $minWidth;
54 |
55 | /**
56 | * The maximum width needed for the image. If specifying a width bigger than the original image,
57 | * the width of the original image is used instead. Default: 3840.
58 | *
59 | * @var ?int
60 | */
61 | protected ?int $maxWidth;
62 |
63 | /**
64 | * The number of breakpoints. Default: 5.
65 | *
66 | * @var ?int
67 | */
68 | protected ?int $maxImages;
69 |
70 | /**
71 | * Defines whether to use auto optimal breakpoints.
72 | *
73 | * @var ?bool
74 | */
75 | public ?bool $autoOptimalBreakpoints = null;
76 | }
77 |
--------------------------------------------------------------------------------
/src/Configuration/TagConfigTrait.php:
--------------------------------------------------------------------------------
1 | setTagConfig(TagConfig::VIDEO_POSTER_FORMAT, $format);
31 | }
32 |
33 |
34 | /**
35 | * Use fetch format transformation ("f_") instead of file extension.
36 | *
37 | * @param bool $useFetchFormat
38 | *
39 | * @return $this
40 | */
41 | public function useFetchFormat($useFetchFormat = true): static
42 | {
43 | return $this->setTagConfig(TagConfig::USE_FETCH_FORMAT, $useFetchFormat);
44 | }
45 |
46 | /**
47 | * Sets the Tag configuration key with the specified value.
48 | *
49 | * @param string $configKey The configuration key.
50 | * @param mixed $configValue THe configuration value.
51 | *
52 | * @return $this
53 | *
54 | * @internal
55 | */
56 | abstract public function setTagConfig($configKey, $configValue): static;
57 | }
58 |
--------------------------------------------------------------------------------
/src/Exception/ConfigurationException.php:
--------------------------------------------------------------------------------
1 | httpClient = new Client();
42 |
43 | if ($configuration === null) {
44 | $configuration = Configuration::instance();
45 | }
46 |
47 | $this->logging = $configuration->logging;
48 | }
49 |
50 | /**
51 | * Retrieves JSON from url.
52 | *
53 | * @param string $url The url
54 | *
55 | *
56 | * @throws Error
57 | * @throws \GuzzleHttp\Exception\GuzzleException
58 | */
59 | public function getJson(string $url): mixed
60 | {
61 | try {
62 | return self::parseJsonResponse($this->httpClient->get($url));
63 | } catch (Error $e) {
64 | $this->getLogger()->critical(
65 | 'Error parsing JSON server response',
66 | [
67 | 'exception' => $e->getMessage(),
68 | 'class' => self::class,
69 | 'url' => $url,
70 | ]
71 | );
72 | throw $e;
73 | }
74 | }
75 |
76 | /**
77 | * Parses JSON response.
78 | *
79 | * @param ResponseInterface $response Response from HTTP request to Cloudinary server
80 | *
81 | *
82 | * @throws Error
83 | */
84 | private static function parseJsonResponse(ResponseInterface $response): mixed
85 | {
86 | try {
87 | $responseJson = JsonUtils::decode($response->getBody());
88 | } catch (InvalidArgumentException $iae) {
89 | $message = sprintf(
90 | 'Error parsing server response (%s) - %s. Got - %s',
91 | $response->getStatusCode(),
92 | $response->getBody(),
93 | $iae
94 | );
95 | throw new Error($message);
96 | }
97 |
98 | return $responseJson;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/Log/LoggerDecorator.php:
--------------------------------------------------------------------------------
1 | config = $config;
36 | }
37 |
38 | /**
39 | * Get the TestHandler (if one has been defined)
40 | *
41 | */
42 | public function getTestHandler(): ?TestHandler
43 | {
44 | return $this->logger?->getTestHandler();
45 |
46 | }
47 |
48 | /**
49 | * Get all Monolog handlers used by this logger
50 | *
51 | * @return HandlerInterface[]
52 | */
53 | public function getHandlers(): array
54 | {
55 | if ($this->logger !== null) {
56 | return $this->logger->getHandlers();
57 | }
58 |
59 | return [];
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Log/LoggersList.php:
--------------------------------------------------------------------------------
1 | enabled === false) {
55 | return null;
56 | }
57 |
58 | $configHash = crc32(serialize($config));
59 |
60 | if (!isset(self::$loggerInstances[$configHash])) {
61 | self::$loggerInstances[$configHash] = new Logger($config);
62 | }
63 |
64 | return self::$loggerInstances[$configHash];
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Tag/Attribute/AudioSourceType.php:
--------------------------------------------------------------------------------
1 | minWidth = $minWidth;
45 | $this->maxWidth = $maxWidth;
46 |
47 | $this->logging = $configuration->logging;
48 | }
49 |
50 | /**
51 | * Serializes to string.
52 | *
53 | * @return string
54 | */
55 | public function __toString()
56 | {
57 | if ($this->minWidth === null && $this->maxWidth === null) {
58 | $message = 'either minWidth or maxWidth is required';
59 | $this->getLogger()->critical($message);
60 |
61 | return '';
62 | }
63 |
64 | if (is_int($this->minWidth) && is_int($this->maxWidth) && $this->minWidth > $this->maxWidth) {
65 | $message = 'minWidth must be less than maxWidth';
66 | $this->getLogger()->critical($message);
67 |
68 | return '';
69 | }
70 |
71 | $mediaQueryConditions = [];
72 |
73 | if (! empty($this->minWidth)) {
74 | $mediaQueryConditions[] = "(min-width: {$this->minWidth}px)";
75 | }
76 |
77 | if (! empty($this->maxWidth)) {
78 | $mediaQueryConditions[] = "(max-width: {$this->maxWidth}px)";
79 | }
80 |
81 | return implode(' and ', $mediaQueryConditions);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Tag/Attribute/Sizes.php:
--------------------------------------------------------------------------------
1 | configuration = $configuration;
35 | }
36 |
37 | /**
38 | * Serializes to string.
39 | *
40 | * @return string
41 | */
42 | public function __toString()
43 | {
44 | return (int)($this->configuration->tag->relativeWidth * 100) . 'vw';
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Tag/Attribute/SourceType.php:
--------------------------------------------------------------------------------
1 | VideoSourceType::OGG];
44 |
45 | /**
46 | * SourceType constructor.
47 | *
48 | * @param string|null $mediaType The media type. Can be self::MEDIA_TYPE_VIDEO or self::MEDIA_TYPE_AUDIO.
49 | * @param string|null $type The type(format) of the source.
50 | * @param array|string|null $codecs The codecs.
51 | */
52 | public function __construct(?string $mediaType = null, ?string $type = null, array|string|null $codecs = null)
53 | {
54 | $this->mediaType = $mediaType;
55 | $this->type = $type;
56 | $this->codecs = ArrayUtils::build($codecs);
57 | }
58 |
59 | /**
60 | * Serializes to string.
61 | *
62 | * @return string
63 | */
64 | public function __toString()
65 | {
66 | if ($this->type === null) {
67 | return '';
68 | }
69 |
70 | $codecsStr = ! empty($this->codecs) ? 'codecs=' . ArrayUtils::implodeFiltered(', ', $this->codecs) : '';
71 |
72 | $typeStr = ArrayUtils::get(self::$typeOverrides, $this->type, $this->type);
73 |
74 | return ArrayUtils::implodeFiltered('; ', ["{$this->mediaType}/{$typeStr}", $codecsStr]);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/Tag/Attribute/VideoSourceType.php:
--------------------------------------------------------------------------------
1 | ` tag to indicate support for Client Hints:
15 | *
16 | * ```
17 | *
18 | * ```
19 | *
20 | * @api
21 | */
22 | class ClientHintsMetaTag extends BaseTag
23 | {
24 | /**
25 | * @var string NAME Mandatory. The name of the tag.
26 | */
27 | public const NAME = 'meta';
28 |
29 | /**
30 | * @var bool IS_VOID Indicates whether the tag is a void (self-closed, without body) tag.
31 | */
32 | protected const IS_VOID = true;
33 |
34 | /**
35 | * @var array $attributes An array of tag attributes.
36 | */
37 | protected array $attributes = [
38 | 'http-equiv' => 'Accept-CH',
39 | 'content' => 'DPR, Viewport-Width, Width',
40 | ];
41 | }
42 |
--------------------------------------------------------------------------------
/src/Tag/FormInputTag.php:
--------------------------------------------------------------------------------
1 |
17 | *
18 | * @internal
19 | */
20 | class FormInputTag extends BaseTag
21 | {
22 | public const NAME = 'input';
23 | protected const IS_VOID = true;
24 |
25 | /**
26 | * @var array $attributes An array of tag attributes.
27 | */
28 | protected array $attributes = ['type' => 'hidden'];
29 |
30 | /**
31 | * FormInputTag constructor.
32 | *
33 | * @param string $name The name of the input tag.
34 | * @param mixed $value The value of the input tag.
35 | */
36 | public function __construct($name, mixed $value)
37 | {
38 | parent::__construct();
39 |
40 | $this->setAttribute('name', $name);
41 | $this->setAttribute('value', $value);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Tag/FormTag.php:
--------------------------------------------------------------------------------
1 | ` tag, for example:
18 | *
19 | *
20 | * ```
21 | *
22 | *
23 | *
24 | *
25 | *
26 | *
27 | * ```
28 | *
29 | * @api
30 | *
31 | */
32 | class FormTag extends BaseConfigurableApiTag
33 | {
34 | public const NAME = 'form';
35 |
36 | /**
37 | * @var array $attributes An array of tag attributes.
38 | */
39 | protected array $attributes = [
40 | 'enctype' => 'multipart/form-data',
41 | 'method' => HttpMethod::POST,
42 | ];
43 |
44 | /**
45 | * Serializes the tag attributes.
46 | *
47 | * @param array $attributes Optional. Additional attributes to add without affecting the tag state.
48 | *
49 | * @internal
50 | */
51 | public function serializeAttributes(array $attributes = []): string
52 | {
53 | $attributes['action'] = $this->uploadApi->getUploadUrl($this->assetType);
54 |
55 | return parent::serializeAttributes($attributes);
56 | }
57 |
58 | /**
59 | * Returns input tags that are appended to the form tag.
60 | *
61 | * For example:
62 | * ```
63 | *
64 | *
65 | *
66 | *
67 | * ```
68 | *
69 | * @param array $additionalContent The additional content.
70 | * @param bool $prependAdditionalContent Whether to prepend additional content (instead of append).
71 | *
72 | *
73 | * @internal
74 | */
75 | public function serializeContent(array $additionalContent = [], bool $prependAdditionalContent = false): string
76 | {
77 | $inputTags = [];
78 | $uploadParams = $this->getUploadParams();
79 |
80 | foreach ($uploadParams as $key => $value) {
81 | $inputTags[] = (string)new FormInputTag($key, $value);
82 | }
83 |
84 | return parent::serializeContent(
85 | ArrayUtils::mergeNonEmpty($inputTags, $additionalContent),
86 | $prependAdditionalContent
87 | );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Tag/ImageTag.php:
--------------------------------------------------------------------------------
1 | ` tag with the `src` attribute set to the transformation URL, optional `srcset` and other
17 | * specified attributes.
18 | *
19 | * For more information, see the [PHP SDK guide](https://cloudinary.com/documentation/php_image_manipulation#deliver_and_transform_images).
20 | *
21 | * @api
22 | */
23 | class ImageTag extends BaseImageTag
24 | {
25 | public const NAME = 'img';
26 | public const IS_VOID = true;
27 |
28 | public const BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
29 | protected const RESPONSIVE_CLASS = 'cld-responsive';
30 | protected const HI_DPI_CLASS = 'cld-hidpi';
31 |
32 | /**
33 | * Serializes the tag attributes.
34 | *
35 | * @param array $attributes Optional. Additional attributes to add without affecting the tag state.
36 | *
37 | */
38 | public function serializeAttributes(array $attributes = []): string
39 | {
40 | if (($this->config->tag->responsive || $this->config->tag->hidpi) && ! $this->config->tag->clientHints) {
41 | $attributes['data-src'] = $this->image;
42 |
43 | $this->addClass($this->config->tag->responsive ? self::RESPONSIVE_CLASS : self::HI_DPI_CLASS);
44 |
45 | $src = $this->config->tag->responsivePlaceholder;
46 | if ($src === 'blank') {
47 | $src = self::BLANK;
48 | }
49 | } else {
50 | $src = $this->image->toUrl($this->additionalTransformation);
51 | }
52 |
53 | ArrayUtils::addNonEmpty($attributes, 'src', $src);
54 |
55 | if (! empty($this->srcset->getBreakpoints())) { // TODO: improve performance here
56 | $attributes['srcset'] = $this->srcset;
57 |
58 | if (! array_key_exists('sizes', $this->attributes)) {
59 | if (is_bool($this->config->tag->sizes)) {
60 | if ($this->config->tag->sizes) {
61 | $attributes['sizes'] = new Sizes($this->config);
62 | }
63 | } elseif (is_string($this->config->tag->sizes)) {
64 | $attributes['sizes'] = $this->config->tag->sizes;
65 | }
66 | }
67 | }
68 |
69 | return parent::serializeAttributes($attributes);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Tag/JsConfigTag.php:
--------------------------------------------------------------------------------
1 | ` tag for JavaScript:
18 | *
19 | * ```
20 | *
23 | * ```
24 | *
25 | * @api
26 | */
27 | class JsConfigTag extends BaseTag
28 | {
29 | public const NAME = 'script';
30 |
31 | /**
32 | * @var array $attributes An array of tag attributes.
33 | */
34 | protected array $attributes = [
35 | 'type' => 'text/javascript',
36 | ];
37 |
38 | /**
39 | * JsConfigTag constructor.
40 | *
41 | * @param Configuration $configuration The configuration instance.
42 | */
43 | public function __construct($configuration = null)
44 | {
45 | parent::__construct();
46 |
47 | if ($configuration === null) {
48 | $configuration = Configuration::instance();
49 | }
50 |
51 | $params = [
52 | 'api_key' => $configuration->cloud->apiKey,
53 | 'cloud_name' => $configuration->cloud->cloudName,
54 | 'private_cdn' => $configuration->url->privateCdn,
55 | 'secure_distribution' => $configuration->url->secureCname, // secure_distribution is still used in v1
56 | 'cdn_subdomain' => $configuration->url->cdnSubdomain,
57 | ];
58 |
59 | $this->setContent('$.cloudinary.config('.json_encode(ArrayUtils::safeFilter($params)).');');
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Tag/TagUtils.php:
--------------------------------------------------------------------------------
1 | url->responsiveWidth);
30 | $useResponsiveBreakpoints = array_key_exists('responsive_breakpoints', $params);
31 |
32 | $noHtmlSizes = $hasLayer || $hasAngle || $cropMode === 'fit' || $cropMode === 'limit' || $responsiveWidth
33 | || $useResponsiveBreakpoints;
34 |
35 | ArrayUtils::addNonEmpty($params, 'width', ArrayUtils::pop($params, 'html_width'));
36 | ArrayUtils::addNonEmpty($params, 'height', ArrayUtils::pop($params, 'html_height'));
37 |
38 | $width = ArrayUtils::get($params, 'width');
39 | if (! (is_null($width) || strlen($width) == 0 || $width && (StringUtils::startsWith($width, 'auto')
40 | || (float)$width < 1 || $noHtmlSizes))) {
41 | ArrayUtils::addNonEmptyFromOther($tagAttributes, 'width', $params);
42 | }
43 |
44 | $height = ArrayUtils::get($params, 'height');
45 | if (! (is_null($height) || strlen($height) == 0 || (float)$height < 1 || $noHtmlSizes)) {
46 | ArrayUtils::addNonEmptyFromOther($tagAttributes, 'height', $params);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Tag/VideoTagDeliveryTypeTrait.php:
--------------------------------------------------------------------------------
1 | ` tag based on a captured frame from the specified video source.
21 | *
22 | * @api
23 | */
24 | class VideoThumbnailTag extends ImageTag
25 | {
26 | /**
27 | * Sets the image of the tag.
28 | *
29 | * @param mixed $image The public ID of the video.
30 | * @param Configuration|null $configuration The Configuration source.
31 | *
32 | */
33 | public function image(mixed $image, ?Configuration $configuration = null): static
34 | {
35 | parent::image(new Video($image, $configuration), $configuration);
36 |
37 | $this->image->setFormat($configuration->tag->videoPosterFormat, $configuration->tag->useFetchFormat);
38 |
39 | return $this;
40 | }
41 |
42 | /**
43 | * Creates a video poster image tag for a video from the provided source and an array of parameters.
44 | *
45 | * @param string $source The public ID of the asset.
46 | * @param array $params The asset parameters.
47 | *
48 | */
49 | public static function fromParams(string $source, array $params = []): VideoThumbnailTag
50 | {
51 | $configuration = self::fromParamsDefaultConfig();
52 |
53 | ArrayUtils::setDefaultValue($params, 'resource_type', AssetType::VIDEO);
54 | ArrayUtils::setDefaultValue($params, 'format', $configuration->tag->videoPosterFormat);
55 |
56 | return parent::fromParams($source, $params);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/tests/Helpers/Addon.php:
--------------------------------------------------------------------------------
1 | accountApiClient = new MockAccountApiClient($configuration);
32 | }
33 |
34 | /**
35 | * Returns a mock api client.
36 | *
37 | * @return MockAccountApiClient
38 | */
39 | public function getApiClient()
40 | {
41 | return $this->accountApiClient;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Helpers/MockAccountApiClient.php:
--------------------------------------------------------------------------------
1 | apiClient = new MockApiClient($configuration);
34 |
35 | $apiV2Configuration = new Configuration($configuration);
36 | $apiV2Configuration->api->apiVersion = '2';
37 |
38 | $this->apiV2Client = new MockApiClient($apiV2Configuration);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/Helpers/MockAnalytics.php:
--------------------------------------------------------------------------------
1 | getApiClient()->mockHandler;
28 | }
29 |
30 | /**
31 | * Returns mock handler.
32 | *
33 | * @return MockHandler
34 | */
35 | public function getV2MockHandler()
36 | {
37 | return $this->getApiV2Client()->mockHandler;
38 | }
39 |
40 | /**
41 | * Returns a mock api client.
42 | *
43 | * @return \Cloudinary\Api\ApiClient|\Cloudinary\Api\UploadApiClient|MockApiClient
44 | */
45 | public function getApiClient()
46 | {
47 | return $this->apiClient;
48 | }
49 |
50 | /**
51 | * Returns a mock api client.
52 | *
53 | * @return \Cloudinary\Api\ApiClient|\Cloudinary\Api\UploadApiClient|MockApiClient
54 | */
55 | public function getApiV2Client()
56 | {
57 | return $this->apiV2Client;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tests/Helpers/MockSearchApi.php:
--------------------------------------------------------------------------------
1 | apiClient = new MockApiClient($configuration);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Helpers/MockSearchFoldersApi.php:
--------------------------------------------------------------------------------
1 | apiClient = new MockApiClient($configuration);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Helpers/MockUploadApi.php:
--------------------------------------------------------------------------------
1 | apiClient = new MockUploadApiClient($configuration);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Helpers/MockUploadApiClient.php:
--------------------------------------------------------------------------------
1 | ping();
24 |
25 | self::assertEquals('ok', $result['status']);
26 | }
27 |
28 | public function testPingAsync()
29 | {
30 | $result = self::$adminApi->pingAsync()->wait();
31 |
32 | self::assertEquals('ok', $result['status']);
33 | }
34 |
35 | public function testConfig()
36 | {
37 | $result = self::$adminApi->config();
38 |
39 | self::assertEquals(Configuration::instance()->cloud->cloudName, $result['cloud_name']);
40 | self::assertArrayNotHasKey('settings', $result);
41 |
42 | $resultWithSettings = self::$adminApi->config(['settings' => 'true']);
43 |
44 | self::assertArrayHasKey('settings', $resultWithSettings);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tests/Integration/Admin/OAuthTest.php:
--------------------------------------------------------------------------------
1 | cloud->oauthToken(self::FAKE_OAUTH_TOKEN);
38 | $adminApi = new AdminApi($config);
39 |
40 | $this->expectExceptionMessage('Invalid token');
41 |
42 | $adminApi->asset(self::$UNIQUE_IMAGE_PUBLIC_ID);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/Integration/Admin/TagsTest.php:
--------------------------------------------------------------------------------
1 | ['tags' => [self::$TAG_WITH_PREFIX]],
39 | ],
40 | ]
41 | );
42 | }
43 |
44 | public static function tearDownAfterClass()
45 | {
46 | self::cleanupTestAssets();
47 |
48 | parent::tearDownAfterClass();
49 | }
50 |
51 | /**
52 | * List tags of images
53 | *
54 | * @throws ApiError
55 | */
56 | public function testListTagsOfImages()
57 | {
58 | $result = self::$adminApi->tags(['max_results' => 2]);
59 |
60 | self::assertObjectStructure($result, ['tags' => IsType::TYPE_ARRAY]);
61 | self::assertCount(2, $result['tags']);
62 | self::assertIsString($result['tags'][0]);
63 | }
64 |
65 | /**
66 | * List all tags with a given prefix
67 | */
68 | public function testListTagsWithPrefix()
69 | {
70 | $result = self::$adminApi->tags(['prefix' => self::$PREFIX_TAG]);
71 |
72 | self::assertObjectStructure($result, ['tags' => IsType::TYPE_ARRAY]);
73 | self::assertCount(1, $result['tags']);
74 | self::assertContains(self::$TAG_WITH_PREFIX, $result['tags']);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/tests/Unit/Admin/AdminApiTest.php:
--------------------------------------------------------------------------------
1 | asset(self::$UNIQUE_TEST_ID, ['accessibility_analysis' => true]);
31 | $lastRequest = $mockAdminApi->getMockHandler()->getLastRequest();
32 |
33 | self::assertRequestQueryStringSubset($lastRequest, ['accessibility_analysis' => '1']);
34 | }
35 |
36 | /**
37 | * Should allow the user to pass accessibility_analysis in the createUploadPreset function.
38 | */
39 | public function testAccessibilityAnalysisUploadPreset()
40 | {
41 | $mockAdminApi = new MockAdminApi();
42 | $mockAdminApi->createUploadPreset(['accessibility_analysis' => true]);
43 | $lastRequest = $mockAdminApi->getMockHandler()->getLastRequest();
44 |
45 | self::assertRequestBodySubset($lastRequest, ['accessibility_analysis' => '1']);
46 | }
47 |
48 | /**
49 | * Should allow listing related assets in the asset function.
50 | */
51 | public function testAssetRelatedAssets()
52 | {
53 | $mockAdminApi = new MockAdminApi();
54 | $mockAdminApi->asset(self::$UNIQUE_TEST_ID, ['related' => true, 'related_next_cursor' => self::NEXT_CURSOR]);
55 | $lastRequest = $mockAdminApi->getMockHandler()->getLastRequest();
56 |
57 | self::assertRequestQueryStringSubset(
58 | $lastRequest,
59 | ['related' => '1', 'related_next_cursor' => self::NEXT_CURSOR]
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tests/Unit/Admin/AnalysisTest.php:
--------------------------------------------------------------------------------
1 | analyze(
32 | "uri",
33 | "captioning",
34 | "https://res.cloudinary.com/demo/image/upload/dog",
35 | ["custom" => ["model_name" => "my_model", "model_version" => 1]]
36 | );
37 |
38 | $lastRequest = $mockAdminApi->getV2MockHandler()->getLastRequest();
39 | $apiV2Configuration = new Configuration();
40 | $apiV2Configuration->api->apiVersion = '2';
41 |
42 | self::assertRequestUrl($lastRequest, '/analysis/analyze/uri', "", $apiV2Configuration);
43 | self::assertRequestJsonBodySubset(
44 | $lastRequest,
45 | [
46 | "analysis_type" => "captioning",
47 | "uri" => "https://res.cloudinary.com/demo/image/upload/dog",
48 | "parameters" => ["custom" => ["model_name" => "my_model", "model_version" => 1]]
49 | ]
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/tests/Unit/Admin/FoldersTest.php:
--------------------------------------------------------------------------------
1 | renameFolder(self::API_TEST_ASSET_ID, self::API_TEST_ASSET_ID2);
35 |
36 | $lastRequest = $mockAdminApi->getMockHandler()->getLastRequest();
37 |
38 | self::assertRequestPut($lastRequest);
39 | self::assertRequestUrl($lastRequest, '/folders/' . self::API_TEST_ASSET_ID);
40 | self::assertRequestBodySubset(
41 | $lastRequest,
42 | [
43 | "to_folder" => self::API_TEST_ASSET_ID2,
44 | ]
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Unit/Admin/OAuthTest.php:
--------------------------------------------------------------------------------
1 | cloud->oauthToken(self::FAKE_OAUTH_TOKEN);
35 |
36 | $adminApi = new MockAdminApi($config);
37 | $adminApi->ping();
38 | $lastRequest = $adminApi->getMockHandler()->getLastRequest();
39 |
40 | self::assertRequestHeaderSubset(
41 | $lastRequest,
42 | [
43 | 'Authorization' => ['Bearer ' . self::FAKE_OAUTH_TOKEN]
44 | ]
45 | );
46 | }
47 |
48 | /**
49 | * Should make a request using `apiKey` and `apiSecret` if an Oauth Token is absent.
50 | */
51 | public function testKeyAndSecretAdminApi()
52 | {
53 | $config = new Configuration(Configuration::instance());
54 | $config->cloud->oauthToken(null);
55 |
56 | $adminApi = new MockAdminApi($config);
57 | $adminApi->ping();
58 | $lastRequest = $adminApi->getMockHandler()->getLastRequest();
59 |
60 | self::assertRequestHeaderSubset(
61 | $lastRequest,
62 | [
63 | 'Authorization' => ['Basic a2V5OnNlY3JldA==']
64 | ]
65 | );
66 | }
67 |
68 | /**
69 | * Should be thrown an exception if `apiKey` and `apiSecret` or an Oauth Token are absent.
70 | */
71 | public function testMissingCredentialsAdminApi()
72 | {
73 | $config = new Configuration(Configuration::instance());
74 | $config->cloud->oauthToken(null);
75 | $config->cloud->apiKey = null;
76 | $config->cloud->apiSecret = null;
77 |
78 | $this->expectException(InvalidArgumentException::class);
79 | $this->expectExceptionMessage('Must supply apiKey');
80 |
81 | $adminApi = new MockAdminApi($config);
82 | $adminApi->ping();
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/tests/Unit/ApiClientTest.php:
--------------------------------------------------------------------------------
1 | postFileAsync('/', '', []);
41 | } catch (Exception $e) {
42 | $message = $e->getMessage();
43 | }
44 |
45 | self::assertStringStartsWith($expectedExceptionMessage, $message);
46 | self::assertObjectLoggedMessage($apiClient, $expectedLogMessage, Monolog::CRITICAL);
47 | }
48 |
49 |
50 | /**
51 | * @throws ReflectionException
52 | */
53 | public function testInvalidApiClientParseJsonResponse()
54 | {
55 | $apiClient = new ApiClient();
56 | $reflectionMethod = new ReflectionMethod(ApiClient::class, 'parseJsonResponse');
57 | $reflectionMethod->setAccessible(true);
58 |
59 | $message = null;
60 | $expectedExceptionMessage = 'Error parsing server response';
61 | try {
62 | $reflectionMethod->invoke($apiClient, new Response(200, [], '{NOT_A_JSON}'));
63 | } catch (Exception $e) {
64 | $message = $e->getMessage();
65 | }
66 |
67 | self::assertStringStartsWith($expectedExceptionMessage, $message);
68 | self::assertObjectLoggedMessage($apiClient, $expectedExceptionMessage, Monolog::ERROR);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/tests/Unit/Asset/AnalyticsTest.php:
--------------------------------------------------------------------------------
1 | expectException(OutOfRangeException::class);
45 | self::invokeNonPublicMethod(MockAnalytics::class, 'encodeVersion', '44.45.46');
46 | }
47 |
48 | public function testSdkAnalyticsSignature()
49 | {
50 | self::assertEquals(
51 | 'BAAJ1uAI',
52 | MockAnalytics::sdkAnalyticsSignature()
53 | );
54 | }
55 |
56 | public function testTechVersion()
57 | {
58 | MockAnalytics::techVersion('12.0');
59 |
60 | self::assertEquals(
61 | 'BAAJ1uAM',
62 | MockAnalytics::sdkAnalyticsSignature()
63 | );
64 |
65 | MockAnalytics::techVersion('12.0.0');
66 |
67 | self::assertEquals(
68 | 'BAAJ1uAM',
69 | MockAnalytics::sdkAnalyticsSignature()
70 | );
71 |
72 | MockAnalytics::techVersion('12');
73 |
74 | self::assertEquals(
75 | 'BAAJ1uM',
76 | MockAnalytics::sdkAnalyticsSignature()
77 | );
78 | }
79 |
80 | public function testSdkAnalyticsSignatureWithIntegration()
81 | {
82 | MockAnalytics::product('B'); // Integrations
83 | MockAnalytics::sdkCode('B'); // Laravel
84 | MockAnalytics::sdkVersion('2.0.0'); // Laravel SDK version
85 | MockAnalytics::techVersion('9.5'); // Laravel version
86 |
87 | self::assertEquals(
88 | 'BBBAACH9',
89 | MockAnalytics::sdkAnalyticsSignature()
90 | );
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/tests/Unit/Asset/AssetTransformationTest.php:
--------------------------------------------------------------------------------
1 | resize(Resize::fill(300, 400));
33 | }
34 |
35 | public function testAssetTransformation()
36 | {
37 | self::assertEquals(
38 | self::$expectedTStr,
39 | (string)(new AssetTransformation(self::$t))
40 | );
41 | }
42 |
43 | public function testAssetTransformationWithExt()
44 | {
45 | self::assertEquals(
46 | self::$expectedTStr . '/' . Format::JPG,
47 | (string)(new AssetTransformation(self::$t, Format::JPG))
48 | );
49 | }
50 |
51 | public function testAssetTransformationWithEmptyExt()
52 | {
53 | self::assertEquals(
54 | self::$expectedTStr . '/',
55 | (string)(new AssetTransformation(self::$t, ''))
56 | );
57 | }
58 |
59 | public function testAssetTransformationFromParams()
60 | {
61 | $params = [
62 | 'crop' => 'fill',
63 | 'width' => 300,
64 | 'height' => 400,
65 | ];
66 |
67 | self::assertEquals(
68 | self::$expectedTStr,
69 | (string)(new AssetTransformation($params))
70 | );
71 |
72 | $params['format'] = Format::JPG;
73 |
74 | self::assertEquals(
75 | self::$expectedTStr . '/' . Format::JPG,
76 | (string)(new AssetTransformation($params))
77 | );
78 |
79 | self::assertEquals(
80 | self::$expectedTStr . '/' . Format::JPG,
81 | (string)AssetTransformation::fromParams($params)
82 | );
83 |
84 | $params['format'] = '';
85 |
86 | self::assertEquals(
87 | self::$expectedTStr . '/',
88 | (string)(new AssetTransformation($params))
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/tests/Unit/Asset/AuthTokenTestCase.php:
--------------------------------------------------------------------------------
1 | importCloudinaryUrl(
35 | $this->cloudinaryUrl.
36 | '?auth_token[duration]='.self::DURATION.
37 | '&auth_token[start_time]='.static::START_TIME.
38 | '&auth_token[key]='.self::AUTH_TOKEN_KEY.
39 | '&url[sign_url]=true'.
40 | '&url[private_cdn]=true'
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Unit/Asset/FileTest.php:
--------------------------------------------------------------------------------
1 | asset->suffix = 'my_favorite_sample';
39 |
40 | self::assertAssetUrl(
41 | 'files/sample/my_favorite_sample.bin',
42 | (string)$f
43 | );
44 |
45 | $fNoFormat = new File(pathinfo(self::FILE_NAME, PATHINFO_FILENAME));
46 |
47 | $fNoFormat->asset->suffix = 'my_favorite_sample';
48 |
49 | self::assertAssetUrl(
50 | 'files/sample/my_favorite_sample',
51 | (string)$fNoFormat
52 | );
53 |
54 | $fNoFormat->deliveryType(DeliveryType::FETCH);
55 |
56 | self::assertErrorThrowing(
57 | static function () use ($fNoFormat) {
58 | return $fNoFormat->toUrl();
59 | }
60 | );
61 | }
62 |
63 | /**
64 | * @throws ReflectionException
65 | */
66 | public function testInvalidFileImportJson()
67 | {
68 | $file = new File(self::FILE_NAME, self::TEST_LOGGING);
69 |
70 | $message = null;
71 | $expectedLogMessage = 'Error importing JSON';
72 | $expectedExceptionMessage = 'JsonException :';
73 | try {
74 | $file->importJson('{NOT_A_JSON}');
75 | } catch (InvalidArgumentException $e) {
76 | $message = $e->getMessage();
77 | }
78 |
79 | self::assertStringStartsWith($expectedExceptionMessage, $message);
80 | self::assertObjectLoggedMessage($file, $expectedLogMessage, Monolog::CRITICAL);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/tests/Unit/Asset/MediaTest.php:
--------------------------------------------------------------------------------
1 | media = new Media(self::IMAGE_NAME);
34 | }
35 |
36 | public function testSimpleMedia()
37 | {
38 | self::assertImageUrl(
39 | self::IMAGE_NAME,
40 | $this->media
41 | );
42 |
43 | self::assertImageUrl(
44 | self::IMAGE_NAME,
45 | $this->media->toUrl()
46 | );
47 | }
48 |
49 | public function testFetchMedia()
50 | {
51 | $image = Media::fetch(self::FETCH_IMAGE_URL);
52 |
53 | self::assertImageUrl(self::FETCH_IMAGE_URL, $image, ['delivery_type' => DeliveryType::FETCH]);
54 | }
55 |
56 | public function testMediaAssetProperties()
57 | {
58 | self::assertAssetUrl(
59 | 'images/' . self::TEST_ASSET_VERSION_STR . '/' . self::URL_SUFFIXED_ASSET_ID . '.' . self::IMG_EXT_GIF,
60 | $this->media
61 | ->version(self::TEST_ASSET_VERSION)
62 | ->suffix(self::URL_SUFFIX)
63 | ->extension(self::IMG_EXT_GIF)
64 | );
65 | }
66 |
67 | public function testMediaAssetSuffixValidation()
68 | {
69 | $this->expectException(UnexpectedValueException::class);
70 | $this->media->suffix('../illegal_suffix.//');
71 | }
72 |
73 | public function testMediaMultipleTypes()
74 | {
75 | self::assertImageUrl(
76 | 'c_fill,g_auto,h_160,w_80/ac_vorbis/' . self::IMAGE_NAME,
77 | $this->media->fill(80, 160, Gravity::auto())->transcode(AudioCodec::vorbis())
78 | );
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/tests/Unit/Asset/SearchAssetTest.php:
--------------------------------------------------------------------------------
1 | expression("resource_type:image AND tags=kitten AND uploaded_at>1d AND bytes>1m")
26 | ->sortBy("public_id", "desc")
27 | ->maxResults(30);
28 |
29 | $b64Query = "eyJleHByZXNzaW9uIjoicmVzb3VyY2VfdHlwZTppbWFnZSBBTkQgdGFncz1raXR0ZW4gQU5EIHVwbG9hZGVkX2F0" .
30 | "PjFkIEFORCBieXRlcz4xbSIsIm1heF9yZXN1bHRzIjozMCwic29ydF9ieSI6W3sicHVibGljX2lkIjoiZGVzYyJ9XX0=";
31 |
32 | $ttl300Sig = "431454b74cefa342e2f03e2d589b2e901babb8db6e6b149abf25bc0dd7ab20b7";
33 | $ttl1000Sig = "25b91426a37d4f633a9b34383c63889ff8952e7ffecef29a17d600eeb3db0db7";
34 |
35 | $nextCursor = self::NEXT_CURSOR;
36 |
37 | # default usage
38 | self::assertAssetUrl(
39 | "search/{$ttl300Sig}/300/{$b64Query}",
40 | $s
41 | );
42 |
43 | # same signature with next cursor
44 | self::assertAssetUrl(
45 | "search/{$ttl300Sig}/300/{$b64Query}/{$nextCursor}",
46 | $s->toUrl(null, self::NEXT_CURSOR)
47 | );
48 |
49 | # with custom ttl and next cursor
50 | self::assertAssetUrl(
51 | "search/{$ttl1000Sig}/1000/{$b64Query}/{$nextCursor}",
52 | $s->toUrl(1000, self::NEXT_CURSOR)
53 | );
54 |
55 | # ttl and cursor are set from the class
56 | self::assertAssetUrl(
57 | "search/{$ttl1000Sig}/1000/{$b64Query}/{$nextCursor}",
58 | $s->ttl(1000)->nextCursor(self::NEXT_CURSOR)
59 | );
60 |
61 | # private cdn
62 | self::assertAssetUrl(
63 | "search/{$ttl1000Sig}/1000/{$b64Query}/{$nextCursor}",
64 | $s->privateCdn(),
65 | ['private_cdn' => true]
66 | );
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tests/Unit/Asset/VideoTest.php:
--------------------------------------------------------------------------------
1 | resize(Scale::scale(new Width(100), 200)->aspectRatio(AspectRatio::ignoreInitialAspectRatio()));
28 |
29 | $t_expected = 'c_scale,fl_ignore_aspect_ratio,h_200,w_100';
30 |
31 | self::assertEquals(
32 | $t_expected,
33 | (string)$v->getTransformation()
34 | );
35 |
36 | self::assertVideoUrl(
37 | "{$t_expected}/" . self::VIDEO_NAME,
38 | (string)$v
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/Unit/Cloudinary/CloudinaryTest.php:
--------------------------------------------------------------------------------
1 | configuration->cloud->cloudName);
28 | self::assertNotNull($c->configuration->cloud->apiKey);
29 | self::assertNotNull($c->configuration->cloud->apiSecret);
30 | }
31 |
32 | public function testCloudinaryUrlNotSet()
33 | {
34 | self::clearEnvironment();
35 |
36 | $this->expectException(InvalidArgumentException::class);
37 |
38 | new Cloudinary(); // Boom!
39 | }
40 |
41 | public function testCloudinaryFromOptions()
42 | {
43 | $c = new Cloudinary(
44 | [
45 | 'cloud' => [
46 | 'cloud_name' => self::CLOUD_NAME,
47 | 'api_key' => self::API_KEY,
48 | 'api_secret' => self::API_SECRET,
49 | ],
50 | ]
51 | );
52 |
53 | self::assertEquals(self::CLOUD_NAME, $c->configuration->cloud->cloudName);
54 | self::assertEquals(self::API_KEY, $c->configuration->cloud->apiKey);
55 | self::assertEquals(self::API_SECRET, $c->configuration->cloud->apiSecret);
56 | }
57 |
58 | public function testCloudinaryFromUrl()
59 | {
60 | $c = new Cloudinary($this->cloudinaryUrl);
61 |
62 | self::assertEquals(self::CLOUD_NAME, $c->configuration->cloud->cloudName);
63 | self::assertEquals(self::API_KEY, $c->configuration->cloud->apiKey);
64 | self::assertEquals(self::API_SECRET, $c->configuration->cloud->apiSecret);
65 | }
66 |
67 | public function testCloudinaryFromConfiguration()
68 | {
69 | self::clearEnvironment();
70 |
71 | $config = new Configuration($this->cloudinaryUrl);
72 |
73 | $c = new Cloudinary($config);
74 |
75 | self::assertEquals(self::CLOUD_NAME, $c->configuration->cloud->cloudName);
76 | self::assertEquals(self::API_KEY, $c->configuration->cloud->apiKey);
77 | self::assertEquals(self::API_SECRET, $c->configuration->cloud->apiSecret);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/tests/Unit/Configuration/CloudConfigTest.php:
--------------------------------------------------------------------------------
1 | cloudinaryUrl);
24 |
25 | self::assertEquals(self::CLOUD_NAME, $cloud->cloudName);
26 |
27 | self::assertEquals(
28 | '',
29 | (string)$cloud
30 | );
31 |
32 | self::assertEquals(
33 | '{"cloud":{"cloud_name":"' . self::CLOUD_NAME . '","api_key":"' . self::API_KEY . '","api_secret":"' .
34 | self::API_SECRET . '"}}',
35 | json_encode($cloud)
36 | );
37 |
38 | self::assertEquals(
39 | '{"cloud":{"cloud_name":"' . self::CLOUD_NAME . '"}}',
40 | json_encode($cloud->jsonSerialize(false)) // exclude sensitive (passwords, etc) keys
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Unit/Configuration/Provisioning/ConfigurationAccountTest.php:
--------------------------------------------------------------------------------
1 | accountUrl);
24 |
25 | self::assertEquals(self::ACCOUNT_ID, $config->provisioningAccount->accountId);
26 | self::assertEquals(self::ACCOUNT_API_KEY, $config->provisioningAccount->provisioningApiKey);
27 | self::assertEquals(self::ACCOUNT_API_SECRET, $config->provisioningAccount->provisioningApiSecret);
28 | }
29 |
30 | public function testAccountConfigFromArray()
31 | {
32 | $config = new ProvisioningConfiguration(
33 | [
34 | 'account_id' => self::ACCOUNT_ID,
35 | 'provisioning_api_key' => self::ACCOUNT_API_KEY,
36 | 'provisioning_api_secret' => self::ACCOUNT_API_SECRET,
37 | ]
38 | );
39 |
40 | self::assertEquals(self::ACCOUNT_ID, $config->provisioningAccount->accountId);
41 | self::assertEquals(self::ACCOUNT_API_KEY, $config->provisioningAccount->provisioningApiKey);
42 | self::assertEquals(self::ACCOUNT_API_SECRET, $config->provisioningAccount->provisioningApiSecret);
43 | }
44 |
45 | public function testAccountConfigFromObject()
46 | {
47 | $config = new ProvisioningConfiguration($this->accountUrl);
48 | $config = new ProvisioningConfiguration($config);
49 |
50 | self::assertEquals(self::ACCOUNT_ID, $config->provisioningAccount->accountId);
51 | self::assertEquals(self::ACCOUNT_API_KEY, $config->provisioningAccount->provisioningApiKey);
52 | self::assertEquals(self::ACCOUNT_API_SECRET, $config->provisioningAccount->provisioningApiSecret);
53 | }
54 |
55 | public function testAccountConfigJsonSerialize()
56 | {
57 | $config = new ProvisioningConfiguration($this->accountUrl);
58 |
59 | $jsonConfig = json_encode($config->jsonSerialize());
60 | $expectedJsonConfig = '{"provisioning_account":{"account_id":"' . self::ACCOUNT_ID .
61 | '","provisioning_api_key":"' . self::ACCOUNT_API_KEY . '","provisioning_api_secret":"' .
62 | self::ACCOUNT_API_SECRET . '"}}';
63 |
64 | self::assertEquals($expectedJsonConfig, $jsonConfig);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/Unit/Configuration/SensitiveKeysSerializationTest.php:
--------------------------------------------------------------------------------
1 | cloud = CloudConfig::fromCloudinaryUrl($this->cloudinaryUrl);
28 | }
29 |
30 | public function testExcludedKeysAreNotSerialized()
31 | {
32 | self::assertStrEquals(
33 | 'cloud[cloud_name]=test123&cloud[api_key]=' . self::API_KEY,
34 | $this->cloud->toString([CloudConfig::API_SECRET])
35 | );
36 |
37 | self::assertStrEquals(
38 | 'cloud[cloud_name]=test123&cloud[api_key]=' . self::API_KEY . '&cloud[api_secret]=' . self::API_SECRET,
39 | $this->cloud->toString()
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/Unit/HttpClientTest.php:
--------------------------------------------------------------------------------
1 | getJson('https://cloudinary.com/');
35 | } catch (Error $e) {
36 | $message = $e->getMessage();
37 | }
38 |
39 | self::assertStringStartsWith($expectedExceptionMessage, $message);
40 | self::assertObjectLoggedMessage($httpClient, $expectedLogMessage, Monolog::CRITICAL);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/Unit/Provisioning/AccessKeysTest.php:
--------------------------------------------------------------------------------
1 | accessKeys(
26 | self::SUB_ACCOUNT_ID,
27 | ['page_size' => 2, 'page' => 1, 'sort_by' => 'name', 'sort_order' => 'asc']
28 | );
29 |
30 | $lastRequest = $mockAccApi->getMockHandler()->getLastRequest();
31 |
32 | self::assertAccountRequestUrl($lastRequest, '/sub_accounts/' . self::SUB_ACCOUNT_ID . '/access_keys');
33 |
34 | self::assertRequestGet($lastRequest);
35 |
36 | self::assertRequestQueryStringSubset($lastRequest, ['page_size' => '2']);
37 | self::assertRequestQueryStringSubset($lastRequest, ['page' => '1']);
38 | self::assertRequestQueryStringSubset($lastRequest, ['sort_by' => 'name']);
39 | self::assertRequestQueryStringSubset($lastRequest, ['sort_order' => 'asc']);
40 | }
41 |
42 | /**
43 | * Should allow generating access keys.
44 | */
45 | public function testGenerateAccessKey()
46 | {
47 | $mockAccApi = new MockAccountApi();
48 |
49 | $mockAccApi->generateAccessKey(
50 | self::SUB_ACCOUNT_ID,
51 | ['enabled' => true, 'name' => 'test_key']
52 | );
53 |
54 | $lastRequest = $mockAccApi->getMockHandler()->getLastRequest();
55 |
56 | self::assertAccountRequestUrl($lastRequest, '/sub_accounts/' . self::SUB_ACCOUNT_ID . '/access_keys');
57 | self::assertRequestPost($lastRequest);
58 |
59 | self::assertRequestJsonBodySubset($lastRequest, ['enabled' => true, 'name' => 'test_key']);
60 | }
61 |
62 | /**
63 | * Should allow updating access keys.
64 | */
65 | public function testUpdateAccessKey()
66 | {
67 | $mockAccApi = new MockAccountApi();
68 |
69 | $mockAccApi->updateAccessKey(
70 | self::SUB_ACCOUNT_ID,
71 | self::API_KEY,
72 | ['enabled' => false, 'name' => 'updated_key']
73 | );
74 |
75 | $lastRequest = $mockAccApi->getMockHandler()->getLastRequest();
76 |
77 | self::assertAccountRequestUrl(
78 | $lastRequest,
79 | '/sub_accounts/' . self::SUB_ACCOUNT_ID . '/access_keys/' . self::API_KEY
80 | );
81 | self::assertRequestPut($lastRequest);
82 |
83 | self::assertRequestJsonBodySubset($lastRequest, ['enabled' => false, 'name' => 'updated_key']);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/tests/Unit/Provisioning/ProvisioningUnitTestCase.php:
--------------------------------------------------------------------------------
1 | accountUrlEnvBackup = getenv(ProvisioningConfiguration::CLOUDINARY_ACCOUNT_URL_ENV_VAR);
35 |
36 | $this->accountUrl = 'account://' . $this::ACCOUNT_API_KEY . ':' . $this::ACCOUNT_API_SECRET . '@'
37 | . $this::ACCOUNT_ID;
38 |
39 | putenv(ProvisioningConfiguration::CLOUDINARY_ACCOUNT_URL_ENV_VAR . '=' . $this->accountUrl);
40 |
41 | ProvisioningConfiguration::instance()->init();
42 | }
43 |
44 | public function tearDown()
45 | {
46 | parent::tearDown();
47 |
48 | putenv(
49 | ProvisioningConfiguration::CLOUDINARY_ACCOUNT_URL_ENV_VAR .
50 | (! empty($this->accountUrlEnvBackup) ? '=' . $this->accountUrlEnvBackup : "")
51 | );
52 | try {
53 | ProvisioningConfiguration::instance()->init();
54 | } catch (ConfigurationException $ce) {
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/Unit/Tag/ClientHintsMetaTagTest.php:
--------------------------------------------------------------------------------
1 | ",
28 | (string)$tag
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Unit/Tag/FormTagTest.php:
--------------------------------------------------------------------------------
1 | configuration = new Configuration();
36 | $this->uploadParams = ['public_id' => self::IMAGE_NAME];
37 | }
38 |
39 | public function testFormTag()
40 | {
41 | $tag = new FormTag($this->configuration, $this->uploadParams);
42 | $tag->addClass('uploader');
43 |
44 | self::assertMatchesRegularExpression(FormTagPatterns::getFormTagPattern(), (string)$tag);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tests/Unit/Tag/JsConfigTagTest.php:
--------------------------------------------------------------------------------
1 | ',
29 | '$.cloudinary.config({"api_key":"' . self::API_KEY . '","cloud_name":"' . self::CLOUD_NAME . '"});',
30 | '',
31 | ]
32 | ),
33 | (string)$tag
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/Unit/Tag/Patterns/FormTagPatterns.php:
--------------------------------------------------------------------------------
1 | \R*
29 | \R*
30 | \R*
31 | \R*
32 | \R*
33 | <\/form>#
34 | TAG;
35 | return str_replace(PHP_EOL, '', $regExp);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/Unit/Tag/Responsive/SrcSetAttributeTest.php:
--------------------------------------------------------------------------------
1 | responsiveBreakpoints->autoOptimalBreakpoints = true;
37 |
38 | $srcset = new SrcSet(self::IMAGE_NAME, $c);
39 |
40 | self::assertStrEquals(
41 | "{$this->prefix}828/sample.png 828w, " .
42 | "{$this->prefix}1366/sample.png 1366w, " .
43 | "{$this->prefix}1536/sample.png 1536w, " .
44 | "{$this->prefix}1920/sample.png 1920w, " .
45 | "{$this->prefix}3840/sample.png 3840w",
46 | $srcset
47 | );
48 | }
49 |
50 | public function testSrcSetAttributeWithCustomBreakpoints()
51 | {
52 | $c = new Configuration(Configuration::instance());
53 |
54 | $c->responsiveBreakpoints->breakpoints = [500, 1000, 1500];
55 |
56 | $srcset = new SrcSet(self::IMAGE_NAME, $c);
57 |
58 | self::assertStrEquals(
59 | "{$this->prefix}500/sample.png 500w, " .
60 | "{$this->prefix}1000/sample.png 1000w, " .
61 | "{$this->prefix}1500/sample.png 1500w",
62 | $srcset
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tests/Unit/Tag/SpriteTagTest.php:
--------------------------------------------------------------------------------
1 | ',
27 | (string)$tag
28 | );
29 | }
30 |
31 | public function testSpriteTagAttributes()
32 | {
33 | $tag = new SpriteTag(self::IMAGE_NAME);
34 | $image = Image::sprite(self::IMAGE_NAME);
35 |
36 | self::assertTagAttributeEquals('text/css', $tag, 'type');
37 | self::assertTagAttributeEquals('stylesheet', $tag, 'rel');
38 | self::assertTagAttributeEquals((string)$image, $tag, 'href');
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/Unit/Tag/TagTestCase.php:
--------------------------------------------------------------------------------
1 | loadHTML($actualTag);
26 | $actualElement = $doc->getElementsByTagName($actualTag::NAME)->item(0);
27 | /** @noinspection PhpPossiblePolymorphicInvocationInspection */
28 | self::assertEquals(
29 | (string)$expectedValue,
30 | $actualElement->getAttribute($attributeName),
31 | "Should contain attribute '$attributeName'"
32 | );
33 | }
34 |
35 | /**
36 | * @param $expectedSrcValue
37 | * @param $actualTag
38 | */
39 | protected static function assertTagSrcEquals($expectedSrcValue, $actualTag)
40 | {
41 | self::assertTagAttributeEquals($expectedSrcValue, $actualTag, 'src');
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Unit/Tag/TestTag.php:
--------------------------------------------------------------------------------
1 | ';
24 |
25 | public function testSimpleVideoThumbnailTag()
26 | {
27 | $tag = new VideoThumbnailTag(self::VIDEO_NAME);
28 |
29 | self::assertEquals(
30 | '
args = $args;
28 | }
29 |
30 | /**
31 | * @return string
32 | */
33 | public function __toString()
34 | {
35 | return substr(strrchr(static::class, '\\'), 1) . '(' . implode(', ', $this->args) . ')';
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/Unit/TestHelpers/TestClassB.php:
--------------------------------------------------------------------------------
1 | logging);
32 | }
33 |
34 | /**
35 | * Generates log entries
36 | */
37 | public function generateLog()
38 | {
39 | $this->info('This is an info level message');
40 | $this->debug('This is a debug level message');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/Unit/UnitTestCase.php:
--------------------------------------------------------------------------------
1 | ['test' => ['level' => 'debug']]];
31 |
32 | const API_TEST_ASSET_ID = '4af5a0d1d4047808528b5425d166c101';
33 | const API_TEST_ASSET_ID2 = '4af5a0d1d4047808528b5425d166c102';
34 | const API_TEST_ASSET_ID3 = '4af5a0d1d4047808528b5425d166c103';
35 |
36 | const NEXT_CURSOR = '8c452e112d4c88ac7c9ffb3a2a41c41bef24';
37 |
38 | protected $cloudinaryUrl;
39 |
40 | private $cldUrlEnvBackup;
41 |
42 | public function setUp()
43 | {
44 | parent::setUp();
45 |
46 | $this->cldUrlEnvBackup = getenv(Configuration::CLOUDINARY_URL_ENV_VAR);
47 |
48 | self::assertNotEmpty($this->cldUrlEnvBackup, 'Please set up CLOUDINARY_URL before running tests!');
49 |
50 | $this->cloudinaryUrl = 'cloudinary://' . $this::API_KEY . ':' . $this::API_SECRET . '@' . $this::CLOUD_NAME;
51 |
52 | putenv(Configuration::CLOUDINARY_URL_ENV_VAR . '=' . $this->cloudinaryUrl);
53 |
54 | $config = ConfigUtils::parseCloudinaryUrl(getenv(Configuration::CLOUDINARY_URL_ENV_VAR));
55 | $config = array_merge($config, self::TEST_LOGGING);
56 | Configuration::instance()->init($config);
57 |
58 | Configuration::instance()->url->analytics(false); // disable analytics for all unit tests
59 | }
60 |
61 | public function tearDown()
62 | {
63 | parent::tearDown();
64 |
65 | putenv(Configuration::CLOUDINARY_URL_ENV_VAR . '=' . $this->cldUrlEnvBackup);
66 | }
67 |
68 | protected static function clearEnvironment()
69 | {
70 | putenv(Configuration::CLOUDINARY_URL_ENV_VAR); // unset CLOUDINARY_URL
71 |
72 | Configuration::instance()->init();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/tests/Unit/Utils/FileUtilsTest.php:
--------------------------------------------------------------------------------
1 | payload; printf("cloudinary://%s:%s@%s", $c->cloudApiKey, $c->cloudApiSecret, $c->cloudName);'
10 |
--------------------------------------------------------------------------------
/tools/get_test_cloud.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
4 |
5 | PHP_VER=$(php -v | head -n 1 | cut -d ' ' -f 2);
6 | SDK_VER=$(php -r "echo json_decode(file_get_contents('composer.json'))->version;")
7 |
8 |
9 | bash ${DIR}/allocate_test_cloud.sh "PHP ${PHP_VER} SDK ${SDK_VER}"
10 |
--------------------------------------------------------------------------------