From 7476ae025921018da9ae2df0a5ede9549e30861f Mon Sep 17 00:00:00 2001 From: phdhiren <71828912+phdhiren@users.noreply.github.com> Date: Fri, 26 Feb 2021 10:53:49 +0530 Subject: [PATCH 1/7] restrict polyfill-mbstring to 1.20.0 / Fix travis-ci (#121) Added support for PHP 7.3 + Fix .travis.yml + restrict polyfill-mbstring to 1.20.0 --- .travis.yml | 13 ++++++++----- composer.json | 3 ++- tests/Test/Entity/MockEntity.php | 20 ++++++++++---------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 78f03593..81e01afa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: php -sudo: false addons: apt: @@ -9,8 +8,9 @@ addons: php: - 7.1 - 7.2 + - 7.3 -matrix: +jobs: fast_finish: true cache: @@ -27,19 +27,22 @@ env: # To prevent failing test runs caused by # "The process "phpunit" exceeded the timeout of 300 seconds. - COMPOSER_PROCESS_TIMEOUT=0 - matrix: + jobs: - DEPENDENCIES="--prefer-lowest" - DEPENDENCIES="" install: # Disable xDebug (but do not remove its configuration, because we need that for code coverage calculation). # Clear the default 6 minutes max execution time limit otherwise test suite fails in case of online tests. - echo -en "max_execution_time = 0\nxdebug.default_enable = 0" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - - composer self-update --rollback - - composer global require hirak/prestissimo:^0.3.7 + - composer self-update --1 + - if [[ $(phpenv version-name) = "7.1" ]] || [[ $(phpenv version-name) = "7.2" ]]; then composer global require hirak/prestissimo:^0.3.7; fi + - travis_retry composer update $COMPOSER_OPTIONS $DEPENDENCIES # Fix PHPUnit tests on PHP >= 7.2 by upgrading Guzzle to >= 6.3.0. # https://github.com/guzzle/guzzle/issues/1973 - if [[ $(phpenv version-name) = "7.2" ]] && [[ "$DEPENDENCIES" = "--prefer-lowest" ]]; then composer require guzzlehttp/guzzle:^6.3.0 --update-with-dependencies $DEPENDENCIES; fi + - if [[ $(phpenv version-name) = "7.3" ]] && [[ "$DEPENDENCIES" = "--prefer-lowest" ]]; then composer require guzzlehttp/guzzle:^6.3.0 --update-with-dependencies $DEPENDENCIES; fi + - if [[ $(phpenv version-name) = "7.4" ]] && [[ "$DEPENDENCIES" = "--prefer-lowest" ]]; then composer require guzzlehttp/guzzle:^6.3.0 --update-with-dependencies $DEPENDENCIES; fi - composer show # We run tests even if the code style analyses fails just to be able get a complete picture about what needs to be diff --git a/composer.json b/composer.json index 09a661ba..814d93ab 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,8 @@ "guzzlehttp/guzzle": "<6.1.0", "guzzlehttp/psr7": "<1.4.1", "phpdocumentor/type-resolver": "<0.2.1", - "vimeo/psalm": ">2.0.13" + "vimeo/psalm": ">2.0.13", + "symfony/polyfill-mbstring": ">1.20.0" }, "autoload": { "psr-4": { diff --git a/tests/Test/Entity/MockEntity.php b/tests/Test/Entity/MockEntity.php index 31539e61..82900011 100644 --- a/tests/Test/Entity/MockEntity.php +++ b/tests/Test/Entity/MockEntity.php @@ -34,6 +34,14 @@ class MockEntity extends Entity use AttributesPropertyAwareTrait; use PropertiesPropertyAwareTrait; + /** + * This property does not have getter or isser so it should be ignored + * by the entity serializer. + * + * @var bool + */ + public $propertyWithoutGetter = false; + /** @var null */ private $nullable; @@ -72,14 +80,6 @@ class MockEntity extends Entity */ private $propertyWithoutSetter = 0; - /** - * This property does not have getter or isser so it should be ignored - * by the entity serializer. - * - * @var bool - */ - private $propertyWithoutGetter = false; - /** @var string[] */ private $variableLengthArgs = []; @@ -125,7 +125,7 @@ public function setDate(?\DateTimeImmutable $date): void } /** - * @inheritdoc + * {@inheritdoc} */ public static function idProperty(): string { @@ -133,7 +133,7 @@ public static function idProperty(): string } /** - * @inheritdoc + * {@inheritdoc} */ public function id(): ?string { From 8adc7eef9fe07468a5a834d2ef2d011061dfe8ec Mon Sep 17 00:00:00 2001 From: phdhiren <71828912+phdhiren@users.noreply.github.com> Date: Tue, 2 Mar 2021 11:26:23 +0530 Subject: [PATCH 2/7] Developer App Analytics page for Hybrid Org #105 (#123) Resolved Error on Developer App Analytics page for Hybrid Org #105 --- .../Management/Controller/StatsController.php | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/src/Api/Management/Controller/StatsController.php b/src/Api/Management/Controller/StatsController.php index 7585d665..5c856b6c 100644 --- a/src/Api/Management/Controller/StatsController.php +++ b/src/Api/Management/Controller/StatsController.php @@ -71,19 +71,28 @@ public function __construct(string $environment, string $organization, ClientInt } /** - * @inheritdoc + * {@inheritdoc} * * @psalm-suppress InvalidOperand - $this->normalizer->normalize() always returns an array. */ public function getMetrics(StatsQueryInterface $query, ?string $optimized = 'js'): array { - $query_params = [ + $query_params = (array) $this->normalizer->normalize($query); + + if ('js' === $optimized && !$this->isHybrid()) { + $query_params += [ '_optimized' => $optimized, - ] + $this->normalizer->normalize($query); + ]; + } + $uri = $this->getBaseEndpointUri()->withQuery(http_build_query($query_params)); $response = $this->responseToArray($this->client->get($uri)); - return $response['Response']; + if ($this->isHybrid()) { + $response['Response']['TimeUnit'] = array_map('intval', $response['Response']['TimeUnit']); + } + + return $response['Response'] ?? []; } /** @@ -132,21 +141,29 @@ public function getOptimisedMetrics(StatsQueryInterface $query): array } /** - * @inheritdoc + * {@inheritdoc} * * @psalm-suppress InvalidOperand - $this->normalizer->normalize() always returns an array. */ public function getMetricsByDimensions(array $dimensions, StatsQueryInterface $query, ?string $optimized = 'js'): array { - $query_params = [ + $query_params = (array) $this->normalizer->normalize($query); + if ('js' === $optimized && !$this->isHybrid()) { + $query_params += [ '_optimized' => $optimized, - ] + $this->normalizer->normalize($query); + ]; + } + $path = $this->getBaseEndpointUri()->getPath() . implode(',', $dimensions); $uri = $this->getBaseEndpointUri()->withPath($path) ->withQuery(http_build_query($query_params)); $response = $this->responseToArray($this->client->get($uri)); - return $response['Response']; + if ($this->isHybrid()) { + $response['Response']['TimeUnit'] = array_map('intval', $response['Response']['TimeUnit']); + } + + return $response['Response'] ?? []; } /** @@ -199,7 +216,7 @@ public function getOptimizedMetricsByDimensions(array $dimensions, StatsQueryInt } /** - * @inheritdoc + * {@inheritdoc} */ public function getOrganisationName(): string { @@ -207,12 +224,16 @@ public function getOrganisationName(): string } /** - * @inheritdoc + * {@inheritdoc} */ protected function getBaseEndpointUri(): UriInterface { - // Slash in the end is always required. - return $this->client->getUriFactory()->createUri("/organizations/{$this->organization}/environments/$this->environment/stats/"); + if ($this->isHybrid()) { + return $this->client->getUriFactory()->createUri("/organizations/{$this->organization}/environments/$this->environment/optimizedStats/"); + } else { + // Slash in the end is always required. + return $this->client->getUriFactory()->createUri("/organizations/{$this->organization}/environments/$this->environment/stats/"); + } } /** @@ -289,4 +310,15 @@ private function fillGapsInMetricsData(bool $tsAscending, array $allTimeUnits, a $metricsData[$key]['values'] = array_values($metricsData[$key]['values']); } } + + /** + * Helper function to check current organization is Hybrid or Edge. + * + * @return bool + * True if current organization is Hybrid otherwise False + */ + private function isHybrid(): bool + { + return ClientInterface::HYBRID_ENDPOINT === $this->getClient()->getEndpoint(); + } } From 66a1ea58395fc7c8786c7932c9742557eac1bf8f Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Wed, 14 Apr 2021 13:37:18 +0530 Subject: [PATCH 3/7] =?UTF-8?q?Closes-#108=20-=20After=20creating=20app=20?= =?UTF-8?q?without=20description=20throwing=20php=20not=E2=80=A6=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Closes-#108 - After creating app without description throwing php notice in hybrid - fixed --- src/Denormalizer/AttributesPropertyDenormalizer.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Denormalizer/AttributesPropertyDenormalizer.php b/src/Denormalizer/AttributesPropertyDenormalizer.php index 635b7f4b..94b86888 100644 --- a/src/Denormalizer/AttributesPropertyDenormalizer.php +++ b/src/Denormalizer/AttributesPropertyDenormalizer.php @@ -26,7 +26,7 @@ class AttributesPropertyDenormalizer extends KeyValueMapDenormalizer { /** - * @inheritdoc + * {@inheritdoc} */ public function supportsDenormalization($data, $type, $format = null) { @@ -46,7 +46,7 @@ public function supportsDenormalization($data, $type, $format = null) * (from the EntityNormalizer for example) * - Internal representation of attributes: ['foo' => 'bar', 'bar' => 'baz'] * - * @inheritdoc + * {@inheritdoc} */ public function denormalize($data, $class, $format = null, array $context = []) { @@ -54,7 +54,7 @@ public function denormalize($data, $class, $format = null, array $context = []) foreach ($data as $key => $item) { if (is_object($item)) { // $data came from the EntityNormalizer. - $flatten[$item->name] = $item->value; + $flatten[$item->name] = $item->value ?? null; } else { $flatten[$key] = $item; } From 2b18f154697e45eae0ed23b9e5ac71818b1ad787 Mon Sep 17 00:00:00 2001 From: phdhiren <71828912+phdhiren@users.noreply.github.com> Date: Mon, 19 Apr 2021 23:26:35 +0530 Subject: [PATCH 4/7] App Analytics page - Fix PHP error on empty data (#133) Fix PHP error in case of empty data for Analytics page --- src/Api/Management/Controller/StatsController.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Api/Management/Controller/StatsController.php b/src/Api/Management/Controller/StatsController.php index 5c856b6c..e154de3d 100644 --- a/src/Api/Management/Controller/StatsController.php +++ b/src/Api/Management/Controller/StatsController.php @@ -89,7 +89,9 @@ public function getMetrics(StatsQueryInterface $query, ?string $optimized = 'js' $response = $this->responseToArray($this->client->get($uri)); if ($this->isHybrid()) { - $response['Response']['TimeUnit'] = array_map('intval', $response['Response']['TimeUnit']); + if (isset($response['Response']['TimeUnit'])) { + $response['Response']['TimeUnit'] = array_map('intval', $response['Response']['TimeUnit']); + } } return $response['Response'] ?? []; @@ -160,7 +162,9 @@ public function getMetricsByDimensions(array $dimensions, StatsQueryInterface $q $response = $this->responseToArray($this->client->get($uri)); if ($this->isHybrid()) { - $response['Response']['TimeUnit'] = array_map('intval', $response['Response']['TimeUnit']); + if (isset($response['Response']['TimeUnit'])) { + $response['Response']['TimeUnit'] = array_map('intval', $response['Response']['TimeUnit']); + } } return $response['Response'] ?? []; From c906b137c15517441439ba2a1c0a18e1fb1db94d Mon Sep 17 00:00:00 2001 From: Raakesh Blokhra Date: Mon, 19 Apr 2021 21:11:39 +0000 Subject: [PATCH 5/7] New Feature NGMint (Apigee X - Monetization) (#135) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * restrict polyfill-mbstring to 1.20.0 / Fix travis-ci in feature-ngmint (#132) * restrict polyfill-mbstring to 1.20.0 * Enabled PHP 7.1, 7.2, 7.3 * FIx travis-ci for feature-ngmint * Code for Purchase,Cancel,Listing of Purchased Products (#131) * Code for Purchase,Cancel,Listing of Purchased Products * phpcs fix * phpcsfixer * code cleanup phpcs * phpcsfix * phpcs fixes * phpcs fix * phpcsfixes Co-authored-by: Hirenkumar Parmar Co-authored-by: phdhiren <71828912+phdhiren@users.noreply.github.com> * Initial Commit for NGMint (ApigeeX 5G) (#130) * Initial Commit for NGMint * Feature ngmint - updated by pulling code from 2.x (#136) * restrict polyfill-mbstring to 1.20.0 / Fix travis-ci (#121) Added support for PHP 7.3 + Fix .travis.yml + restrict polyfill-mbstring to 1.20.0 * Developer App Analytics page for Hybrid Org #105 (#123) Resolved Error on Developer App Analytics page for Hybrid Org #105 * Closes-#108 - After creating app without description throwing php not… (#125) * Closes-#108 - After creating app without description throwing php notice in hybrid - fixed * App Analytics page - Fix PHP error on empty data (#133) Fix PHP error in case of empty data for Analytics page Co-authored-by: phdhiren <71828912+phdhiren@users.noreply.github.com> Co-authored-by: Shishir <75600200+shishir-intelli@users.noreply.github.com> Co-authored-by: phdhiren <71828912+phdhiren@users.noreply.github.com> Co-authored-by: divya-intelli <75604843+divya-intelli@users.noreply.github.com> Co-authored-by: Hirenkumar Parmar Co-authored-by: Shishir <75600200+shishir-intelli@users.noreply.github.com> --- .../Controller/AcceptedRatePlanController.php | 171 ++++++++++++++++++ .../AcceptedRatePlanControllerInterface.php | 69 +++++++ .../Controller/ApiProductController.php | 162 +++++++++++++++++ .../ApiProductControllerInterface.php | 86 +++++++++ .../DeveloperAcceptedRatePlanController.php | 104 +++++++++++ .../ApigeeX/Controller/ListingHelperTrait.php | 60 ++++++ .../PaginatedListingHelperTrait.php | 60 ++++++ .../ApigeeX/Controller/RatePlanController.php | 124 +++++++++++++ .../RatePlanControllerInterface.php | 59 ++++++ .../AcceptedRatePlanDenormalizer.php | 55 ++++++ .../Denormalizer/ApiProductDenormalizer.php | 57 ++++++ .../DeveloperAcceptedRatePlanDenormalizer.php | 51 ++++++ .../Denormalizer/RatePlanDenormalizer.php | 77 ++++++++ .../RatePlanDenormalizerFactory.php | 96 ++++++++++ .../Denormalizer/RatePlanRateDenormalizer.php | 60 ++++++ .../StandardRatePlanDenormalizer.php | 70 +++++++ src/Api/ApigeeX/Entity/AcceptedRatePlan.php | 94 ++++++++++ .../Entity/AcceptedRatePlanInterface.php | 41 +++++ src/Api/ApigeeX/Entity/ApiProduct.php | 31 ++++ .../ApigeeX/Entity/ApiProductInterface.php | 30 +++ .../Entity/DeveloperAcceptedRatePlan.php | 29 +++ .../DeveloperAcceptedRatePlanInterface.php | 25 +++ .../Property/ApiProductPropertyAwareTrait.php | 44 +++++ .../Property/ApiProductPropertyInterface.php | 35 ++++ .../BillingPeriodPropertyAwareTrait.php | 46 +++++ .../BillingPeriodPropertyInterface.php | 35 ++++ ...nsumptionPricingTypePropertyAwareTrait.php | 46 +++++ ...onsumptionPricingTypePropertyInterface.php | 35 ++++ .../CurrencyCodePropertyAwareTrait.php | 46 +++++ .../CurrencyCodePropertyInterface.php | 35 ++++ .../Property/EndTimePropertyAwareTrait.php | 48 +++++ .../Property/EndTimePropertyInterface.php | 32 ++++ .../FixedFeeFrequencyPropertyAwareTrait.php | 46 +++++ .../FixedFeeFrequencyPropertyInterface.php | 35 ++++ .../Property/NanosPropertyAwareTrait.php | 48 +++++ .../Property/NanosPropertyInterface.php | 35 ++++ .../PaymentFundingModelPropertyAwareTrait.php | 46 +++++ .../PaymentFundingModelPropertyInterface.php | 35 ++++ .../RevenueShareTypePropertyAwareTrait.php | 46 +++++ .../RevenueShareTypePropertyInterface.php | 35 ++++ .../Property/StartTimePropertyAwareTrait.php | 48 +++++ .../Property/StartTimePropertyInterface.php | 32 ++++ .../Property/UnitsPropertyAwareTrait.php | 46 +++++ .../Property/UnitsPropertyInterface.php | 35 ++++ src/Api/ApigeeX/Entity/RatePlan.php | 160 ++++++++++++++++ src/Api/ApigeeX/Entity/RatePlanInterface.php | 107 +++++++++++ .../Entity/RatePlanRevisionInterface.php | 32 ++++ src/Api/ApigeeX/Entity/StandardRatePlan.php | 23 +++ .../Entity/StandardRatePlanInterface.php | 23 +++ .../Entity/StandardRatePlanRevision.php | 28 +++ .../NameConverter/RatePlanNameConverter.php | 43 +++++ .../Normalizer/AcceptedRatePlanNormalizer.php | 51 ++++++ .../Normalizer/ApiProductNormalizer.php | 71 ++++++++ .../ApigeeX/Normalizer/RatePlanNormalizer.php | 83 +++++++++ .../Normalizer/RatePlanNormalizerFactory.php | 96 ++++++++++ .../Normalizer/RatePlanRateNormalizer.php | 53 ++++++ .../Normalizer/StandardRatePlanNormalizer.php | 48 +++++ .../Serializer/AcceptedRatePlanSerializer.php | 50 +++++ .../Serializer/ApiProductSerializer.php | 42 +++++ .../ApigeeX/Serializer/RatePlanSerializer.php | 51 ++++++ .../Structure/ConsumptionPricingRate.php | 98 ++++++++++ src/Api/ApigeeX/Structure/Fee.php | 36 ++++ .../ApigeeX/Structure/FixedRecurringFee.php | 36 ++++ src/Api/ApigeeX/Structure/RatePlanXFee.php | 36 ++++ .../ApigeeX/Structure/RevenueShareRates.php | 100 ++++++++++ .../Normalizer/EntityNormalizer.php | 8 +- src/Controller/AbstractEntityController.php | 14 +- .../EntityListingControllerTrait.php | 4 + 68 files changed, 3789 insertions(+), 4 deletions(-) create mode 100755 src/Api/ApigeeX/Controller/AcceptedRatePlanController.php create mode 100755 src/Api/ApigeeX/Controller/AcceptedRatePlanControllerInterface.php create mode 100755 src/Api/ApigeeX/Controller/ApiProductController.php create mode 100755 src/Api/ApigeeX/Controller/ApiProductControllerInterface.php create mode 100755 src/Api/ApigeeX/Controller/DeveloperAcceptedRatePlanController.php create mode 100755 src/Api/ApigeeX/Controller/ListingHelperTrait.php create mode 100755 src/Api/ApigeeX/Controller/PaginatedListingHelperTrait.php create mode 100755 src/Api/ApigeeX/Controller/RatePlanController.php create mode 100755 src/Api/ApigeeX/Controller/RatePlanControllerInterface.php create mode 100755 src/Api/ApigeeX/Denormalizer/AcceptedRatePlanDenormalizer.php create mode 100755 src/Api/ApigeeX/Denormalizer/ApiProductDenormalizer.php create mode 100755 src/Api/ApigeeX/Denormalizer/DeveloperAcceptedRatePlanDenormalizer.php create mode 100755 src/Api/ApigeeX/Denormalizer/RatePlanDenormalizer.php create mode 100755 src/Api/ApigeeX/Denormalizer/RatePlanDenormalizerFactory.php create mode 100755 src/Api/ApigeeX/Denormalizer/RatePlanRateDenormalizer.php create mode 100755 src/Api/ApigeeX/Denormalizer/StandardRatePlanDenormalizer.php create mode 100755 src/Api/ApigeeX/Entity/AcceptedRatePlan.php create mode 100755 src/Api/ApigeeX/Entity/AcceptedRatePlanInterface.php create mode 100755 src/Api/ApigeeX/Entity/ApiProduct.php create mode 100755 src/Api/ApigeeX/Entity/ApiProductInterface.php create mode 100755 src/Api/ApigeeX/Entity/DeveloperAcceptedRatePlan.php create mode 100755 src/Api/ApigeeX/Entity/DeveloperAcceptedRatePlanInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/ApiProductPropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/ApiProductPropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/BillingPeriodPropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/BillingPeriodPropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/ConsumptionPricingTypePropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/ConsumptionPricingTypePropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/CurrencyCodePropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/CurrencyCodePropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/EndTimePropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/EndTimePropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/FixedFeeFrequencyPropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/FixedFeeFrequencyPropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/NanosPropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/NanosPropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/PaymentFundingModelPropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/PaymentFundingModelPropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/RevenueShareTypePropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/RevenueShareTypePropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/StartTimePropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/StartTimePropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/Property/UnitsPropertyAwareTrait.php create mode 100755 src/Api/ApigeeX/Entity/Property/UnitsPropertyInterface.php create mode 100755 src/Api/ApigeeX/Entity/RatePlan.php create mode 100755 src/Api/ApigeeX/Entity/RatePlanInterface.php create mode 100755 src/Api/ApigeeX/Entity/RatePlanRevisionInterface.php create mode 100755 src/Api/ApigeeX/Entity/StandardRatePlan.php create mode 100755 src/Api/ApigeeX/Entity/StandardRatePlanInterface.php create mode 100755 src/Api/ApigeeX/Entity/StandardRatePlanRevision.php create mode 100755 src/Api/ApigeeX/NameConverter/RatePlanNameConverter.php create mode 100755 src/Api/ApigeeX/Normalizer/AcceptedRatePlanNormalizer.php create mode 100755 src/Api/ApigeeX/Normalizer/ApiProductNormalizer.php create mode 100755 src/Api/ApigeeX/Normalizer/RatePlanNormalizer.php create mode 100755 src/Api/ApigeeX/Normalizer/RatePlanNormalizerFactory.php create mode 100755 src/Api/ApigeeX/Normalizer/RatePlanRateNormalizer.php create mode 100755 src/Api/ApigeeX/Normalizer/StandardRatePlanNormalizer.php create mode 100755 src/Api/ApigeeX/Serializer/AcceptedRatePlanSerializer.php create mode 100755 src/Api/ApigeeX/Serializer/ApiProductSerializer.php create mode 100755 src/Api/ApigeeX/Serializer/RatePlanSerializer.php create mode 100755 src/Api/ApigeeX/Structure/ConsumptionPricingRate.php create mode 100755 src/Api/ApigeeX/Structure/Fee.php create mode 100755 src/Api/ApigeeX/Structure/FixedRecurringFee.php create mode 100755 src/Api/ApigeeX/Structure/RatePlanXFee.php create mode 100755 src/Api/ApigeeX/Structure/RevenueShareRates.php diff --git a/src/Api/ApigeeX/Controller/AcceptedRatePlanController.php b/src/Api/ApigeeX/Controller/AcceptedRatePlanController.php new file mode 100755 index 00000000..b42202aa --- /dev/null +++ b/src/Api/ApigeeX/Controller/AcceptedRatePlanController.php @@ -0,0 +1,171 @@ +getAcceptedRatePlans(); + } + + /** + * {@inheritdoc} + */ + public function getPaginatedAcceptedRatePlanList(int $limit = null, int $page = 1): array + { + $query_params = [ + 'page' => $page, + ]; + + if (null !== $limit) { + $query_params['size'] = $limit; + } + + return $this->getAcceptedRatePlans($query_params); + } + + /** + * {@inheritdoc} + */ + public function acceptRatePlan(RatePlanInterface $ratePlan): AcceptedRatePlanInterface + { + $rc = new ReflectionClass($this->getEntityClass()); + /** @var \Apigee\Edge\Api\ApigeeX\Entity\AcceptedRatePlanInterface $acceptedRatePlan */ + $acceptedRatePlan = $rc->newInstance( + [ + 'ratePlan' => $ratePlan, + ] + ); + + $payload = $this->getEntitySerializer()->serialize($acceptedRatePlan, 'json'); + + $tmp = json_decode($payload, true); + + $payload = json_encode($tmp); + + $response = $this->client->post($this->getBaseEndpointUri(), $payload); + $this->getEntitySerializer()->setPropertiesFromResponse($response, $acceptedRatePlan); + + return $acceptedRatePlan; + } + + /** + * {@inheritdoc} + * + * @psalm-suppress PossiblyNullArgument - id is not null in this context. + */ + public function updateSubscription(AcceptedRatePlanInterface $acceptedRatePlan): void + { + $id = $acceptedRatePlan->getName(); + $response = $this->client->post($this->getEntityCancelEndpointUri($id)); + } + + /** + * Builds context for the entity normalizer. + * + * Allows controllers to add extra metadata to the payload. + * + * @return array + */ + abstract protected function buildContextForEntityTransformerInCreate(): array; + + /** + * Returns the URI for listing accepted rate plans. + * + * We have to introduce this because it is not regular that an entity + * has more than one listing endpoint so getBaseEntityEndpoint() was + * enough until this time. + * + * @return \Psr\Http\Message\UriInterface + */ + abstract protected function getAcceptedRatePlansEndpoint(): UriInterface; + + /** + * Allows to alter payload before it gets sent to the API. + * + * @param array $payload + * API request payload. + */ + protected function alterRequestPayload(array &$payload, AcceptedRatePlanInterface $acceptedRatePlan): void + { + } + + /** + * Helper function for listing accepted rate plans. + * + * @param array $query_params + * Additional query parameters. + * + * @return \Apigee\Edge\Api\ApigeeX\Entity\AcceptedRatePlanInterface[] + * + * @psalm-suppress PossiblyNullArrayOffset - id() does not return null here. + */ + private function getAcceptedRatePlans(array $query_params = []): array + { + $entities = []; + + foreach ($this->getRawList($this->getAcceptedRatePlansEndpoint()->withQuery(http_build_query($query_params))) as $item) { + // Added ID as name since in ApigeeX name field gives the id + $item->id = (!isset($item->id)) ? $item->name : ''; + + /** @var \Apigee\Edge\Entity\EntityInterface $tmp */ + $tmp = $this->getEntitySerializer()->denormalize( + $item, + AcceptedRatePlanInterface::class, + 'json' + ); + + $entities[$tmp->id()] = $tmp; + } + + return $entities; + } +} diff --git a/src/Api/ApigeeX/Controller/AcceptedRatePlanControllerInterface.php b/src/Api/ApigeeX/Controller/AcceptedRatePlanControllerInterface.php new file mode 100755 index 00000000..584f6b49 --- /dev/null +++ b/src/Api/ApigeeX/Controller/AcceptedRatePlanControllerInterface.php @@ -0,0 +1,69 @@ +getAvailablexApiProducts('developers', $developerId, $active, $allAvailable); + } + + /** + * {@inheritdoc} + */ + public function getAvailableApixProductsByCompany(string $company, bool $active = false, bool $allAvailable = true): array + { + return $this->getAvailablexApiProducts('companies', $company, $active, $allAvailable); + } + + /** + * {@inheritdoc} + */ + public function getEligibleProductsByDeveloper(string $entityId): array + { + return $this->getEligibleProducts('developers', $entityId); + } + + /** + * {@inheritdoc} + */ + protected function getEntityClass(): string + { + return ApiProduct::class; + } + + /** + * {@inheritdoc} + */ + protected function getBaseEndpointUri(): UriInterface + { + return $this->client->getUriFactory()->createUri("/organizations/{$this->organization}/apiproducts"); + } + + private function getAvailablexApiProducts(string $type, string $id, bool $active = false, bool $allAvailable = true): array + { + $id = rawurlencode($id); + + return $this->listEntities($this->client->getUriFactory()->createUri("/organizations/{$this->organization}/apiproducts")->withQuery(http_build_query([ + 'expand' => $active ? 'true' : 'false', + ]))); + } + + /** + * Returns eligible products of a developer or a company. + * + * @param string $type + * Either "developers" or "companies". + * @param string $entityId + * Id of a developer or company. + * + * @return \Apigee\Edge\Api\Monetization\Entity\ApiProductInterface[] + * List of eligible API products. + * + * @psalm-suppress PossiblyNullArrayOffset id() is not null. + */ + private function getEligibleProducts(string $type, string $entityId): array + { + $entityId = rawurlencode($entityId); + $products = []; + + $subscriptions = []; + $subscribed_product_ids = []; + if ('developers' == $type) { + // Developer subscriptions. + /** @var \Apigee\Edge\Api\ApigeeX\Controller\DeveloperAcceptedRatePlanController $dev_accepted_rateplan */ + $dev_accepted_rateplan = new DeveloperAcceptedRatePlanController($entityId, $this->organization, $this->client); + $subscriptions = $dev_accepted_rateplan->getAllAcceptedRatePlans(); + + foreach ($subscriptions as $subscription) { + if (null === $subscription->getendTime()) { + $subscribed_product_ids[$subscription->getapiproduct()] = $subscription->getapiproduct(); + } + } + } + + $current_ms = substr(microtime(true) * 1000, 0); + + foreach ($this->getAvailablexApiProducts($type, $entityId, true) as $item) { + // Create a new rate plan controller. + /** @var \Apigee\Edge\Api\ApigeeX\Controller\RatePlanController $rateplan */ + $rateplan = new RatePlanController($item->id(), $this->organization, $this->client); + + if (empty($rateplan->getEntities())) { + // Free products - No rateplan. + $products[$item->id()] = $item; + } elseif (in_array($item->id(), $subscribed_product_ids)) { + // Subscribed products. + $products[$item->id()] = $item; + } else { + foreach ($rateplan->getEntities() as $plan) { + if (null !== $plan->getendTime() && $plan->getendTime() < $current_ms) { + //Free product - No active rateplan + $products[$item->id()] = $item; + } + } + } + } + + return $products; + } +} diff --git a/src/Api/ApigeeX/Controller/ApiProductControllerInterface.php b/src/Api/ApigeeX/Controller/ApiProductControllerInterface.php new file mode 100755 index 00000000..5cf24ba7 --- /dev/null +++ b/src/Api/ApigeeX/Controller/ApiProductControllerInterface.php @@ -0,0 +1,86 @@ +developer = $developerId; + } + + /** + * {@inheritdoc} + */ + protected function getBaseEndpointUri(): UriInterface + { + $developerId = rawurlencode($this->developer); + + return $this->client->getUriFactory()->createUri("/organizations/{$this->organization}/developers/{$developerId}/subscriptions"); + } + + /** + * {@inheritdoc} + */ + protected function getEntityClass(): string + { + return DeveloperAcceptedRatePlan::class; + } + + /** + * {@inheritdoc} + */ + protected function buildContextForEntityTransformerInCreate(): array + { + $context = []; + $context[EntityNormalizer::MINT_ENTITY_REFERENCE_PROPERTY_VALUES]['Developer'] = $this->developer; + + return $context; + } + + /** + * {@inheritdoc} + */ + protected function getAcceptedRatePlansEndpoint(): UriInterface + { + $developerId = rawurlencode($this->developer); + + return $this->client->getUriFactory()->createUri("/organizations/{$this->organization}/developers/{$developerId}/subscriptions"); + } + + /** + * {@inheritdoc} + * + * @psalm-suppress UndefinedMethod - getDeveloper() exists on the annotated + * interface. + */ + protected function alterRequestPayload(array &$payload, AcceptedRatePlanInterface $acceptedRatePlan): void + { + /* @var \Apigee\Edge\Api\Monetization\Entity\XDeveloperAcceptedRatePlanInterface $acceptedRatePlan */ + // We should prefer developer email addresses over developer ids + // (UUIDs) when we are communicating with the Monetization API. + // @see https://github.com/apigee/apigee-client-php/issues/36 + $payload['developer']['id'] = $acceptedRatePlan->getDeveloper()->getEmail(); + } +} diff --git a/src/Api/ApigeeX/Controller/ListingHelperTrait.php b/src/Api/ApigeeX/Controller/ListingHelperTrait.php new file mode 100755 index 00000000..b415f7ac --- /dev/null +++ b/src/Api/ApigeeX/Controller/ListingHelperTrait.php @@ -0,0 +1,60 @@ +responseArrayToArrayOfEntities($this->getRawList($uri)); + } + + /** + * Returns a raw API response as an array of a listing API endpoint. + * + * @param \Psr\Http\Message\UriInterface $uri + * URI of the endpoint where the request should be sent. + * + * @return array + * API response as an array. + */ + protected function getRawList(UriInterface $uri): array + { + $response = $this->getClient()->get($uri); + $responseArray = $this->responseToArray($response); + + //ApigeeX can return empty array. + if (empty($responseArray)) { + return $responseArray; + } + + // Ignore entity type key from response, ex.: product. + return reset($responseArray); + } + + abstract protected function responseToArray(ResponseInterface $response, bool $expandCompatibility = false): array; + + abstract protected function responseArrayToArrayOfEntities(array $responseArray, string $keyGetter = 'id'): array; +} diff --git a/src/Api/ApigeeX/Controller/PaginatedListingHelperTrait.php b/src/Api/ApigeeX/Controller/PaginatedListingHelperTrait.php new file mode 100755 index 00000000..b596b161 --- /dev/null +++ b/src/Api/ApigeeX/Controller/PaginatedListingHelperTrait.php @@ -0,0 +1,60 @@ +getQuery(), $query_params); + $query_params['expand'] = 'true'; + + // This makes easier testing and also creates a query parameter list + // that is easy to read. + ksort($query_params); + + return $this->listEntities($uri->withQuery(http_build_query($query_params))); + } + + protected function listEntitiesInRange(UriInterface $uri, int $limit = null, int $page = 1): array + { + // Do not lose already set query parameters. + $query_params = []; + parse_str($uri->getQuery(), $query_params); + $query_params += [ + 'page' => $page, + ]; + + if (null !== $limit) { + $query_params['size'] = $limit; + } + + // This makes easier testing and also creates a query parameter list + // that is easy to read. + ksort($query_params); + + return $this->listEntities($uri->withQuery(http_build_query($query_params))); + } +} diff --git a/src/Api/ApigeeX/Controller/RatePlanController.php b/src/Api/ApigeeX/Controller/RatePlanController.php new file mode 100755 index 00000000..8c458715 --- /dev/null +++ b/src/Api/ApigeeX/Controller/RatePlanController.php @@ -0,0 +1,124 @@ +apiProduct = $apiProduct; + $entitySerializer = $entitySerializer ?? new RatePlanSerializer(); + parent::__construct($organization, $client, $entitySerializer); + } + + /** + * {@inheritdoc} + */ + public function getEntities(?bool $showCurrentOnly = null, ?bool $showPrivate = null, ?bool $showStandardOnly = null): array + { + $query_params = [ + 'expand' => 'true', + 'state' => 'PUBLISHED', + ]; + + $uri = $this->getBaseEndpointUri()->withQuery(http_build_query($query_params)); + $response = $this->client->get($uri); + $responseArray = $this->responseToArray($response); + // Ignore entity type key from response, ex.: product. + $responseArray = reset($responseArray); + + //XProduct is not monetized and we skip it. + if (empty($responseArray)) { + return []; + } + + return $this->responseArrayToArrayOfEntities($responseArray); + } + + /** + * {@inheritdoc} + * + * Use RatePlanRevisionBuilder that makes it easier way to create + * new rate plan revisions. + * + * @psalm-suppress PossiblyNullArgument - id is not null in this context. + */ + public function createNewRevision(RatePlanRevisionInterface $entity): void + { + $payload = $this->getEntitySerializer()->serialize($entity, 'json'); + $response = $this->getClient()->post($this->getEntityEndpointUri($entity->getPreviousRatePlanRevision()->id()) . '/revision', $payload); + $this->getEntitySerializer()->setPropertiesFromResponse($response, $entity); + } + + /** + * {@inheritdoc} + */ + protected function getBaseEndpointUri(): UriInterface + { + return $this->client->getUriFactory()->createUri("/organizations/{$this->organization}/apiproducts/{$this->apiProduct}/rateplans"); + } + + /** + * {@inheritdoc} + */ + protected function getEntityClass(): string + { + return RatePlanInterface::class; + } + + /** + * {@inheritDoc} + */ + protected function buildEntityCreatePayload(EntityInterface $entity, array $context = []): string + { + $context[EntityNormalizer::MINT_ENTITY_REFERENCE_PROPERTY_VALUES]['monetizationPackage'] = $this->apiProduct; + + return $this->baseBuildEntityCreatePayload($entity, $context); + } +} diff --git a/src/Api/ApigeeX/Controller/RatePlanControllerInterface.php b/src/Api/ApigeeX/Controller/RatePlanControllerInterface.php new file mode 100755 index 00000000..c8d2b5a7 --- /dev/null +++ b/src/Api/ApigeeX/Controller/RatePlanControllerInterface.php @@ -0,0 +1,59 @@ +developerAcceptedRatePlanClass, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + if (parent::supportsDenormalization($data, $type, $format)) { + return true; + } + + return false; + } +} diff --git a/src/Api/ApigeeX/Denormalizer/RatePlanDenormalizer.php b/src/Api/ApigeeX/Denormalizer/RatePlanDenormalizer.php new file mode 100755 index 00000000..a7a0acd3 --- /dev/null +++ b/src/Api/ApigeeX/Denormalizer/RatePlanDenormalizer.php @@ -0,0 +1,77 @@ +denormalizers = array_merge($denormalizers, [ + new StandardRatePlanDenormalizer(), + new DeveloperRatePlanDenormalizer(), + new CompanyRatePlanDenormalizer(), + new DeveloperCategoryRatePlanDenormalizer(), + ]); + } + + /** + * {@inheritdoc} + * + * @psalm-suppress InvalidNullableReturnType - There are going to be at + * least one denormalizer always that can denormalize data here. + */ + public function denormalize($data, $class, $format = null, array $context = []) + { + foreach ($this->denormalizers as $denormalizer) { + // Return the result from the first denormalizer that can + // denormalize this. + if ($denormalizer->supportsDenormalization($data, $class, $format)) { + return $denormalizer->denormalize($data, $class, $format, $context); + } + } + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + foreach ($this->denormalizers as $denormalizer) { + if ($denormalizer->supportsDenormalization($data, $type, $format)) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function setSerializer(SerializerInterface $serializer): void + { + $this->traitSetSerializer($serializer); + foreach ($this->denormalizers as $denormalizer) { + if ($denormalizer instanceof SerializerAwareInterface) { + $denormalizer->setSerializer($serializer); + } + } + } +} diff --git a/src/Api/ApigeeX/Denormalizer/RatePlanRateDenormalizer.php b/src/Api/ApigeeX/Denormalizer/RatePlanRateDenormalizer.php new file mode 100755 index 00000000..2a18296e --- /dev/null +++ b/src/Api/ApigeeX/Denormalizer/RatePlanRateDenormalizer.php @@ -0,0 +1,60 @@ +type) { + return parent::denormalize($denormalized, $this->revShareClass, $format, $context); + } elseif (RatePlanRate::TYPE_RATECARD === $data->type) { + return parent::denormalize($denormalized, $this->rateCardClass, $format, $context); + } + + throw new UnexpectedValueException(sprintf('Unexpected rate plan rate type with "%s".', $data->type)); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + // Do not apply this on array objects. ArrayDenormalizer takes care of them. + if ('[]' === substr($type, -2)) { + return false; + } + + return RatePlanRate::class === $type || $type instanceof RatePlanRate; + } +} diff --git a/src/Api/ApigeeX/Denormalizer/StandardRatePlanDenormalizer.php b/src/Api/ApigeeX/Denormalizer/StandardRatePlanDenormalizer.php new file mode 100755 index 00000000..063985cc --- /dev/null +++ b/src/Api/ApigeeX/Denormalizer/StandardRatePlanDenormalizer.php @@ -0,0 +1,70 @@ +parentRatePlan)) { + return parent::denormalize($data, $this->standardRatePlanRevisionClass, $format, $context); + } + + return parent::denormalize($data, $this->standardRatePlanClass, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + // Do not apply this on array objects. ArrayDenormalizer takes care of them. + if ('[]' === substr($type, -2)) { + return false; + } + + if (parent::supportsDenormalization($data, $type, $format)) { + //return RatePlanInterface::TYPE_STANDARD == $data->type; + return RatePlanInterface::TYPE_STANDARD == 'STANDARD'; + } + + return false; + } +} diff --git a/src/Api/ApigeeX/Entity/AcceptedRatePlan.php b/src/Api/ApigeeX/Entity/AcceptedRatePlan.php new file mode 100755 index 00000000..b9e6cb87 --- /dev/null +++ b/src/Api/ApigeeX/Entity/AcceptedRatePlan.php @@ -0,0 +1,94 @@ +lastModifiedAt; + } + + /** + * @param string $updated + * + * @internal + */ + public function setLastModifiedAt(?string $lastModifiedAt): void + { + $this->lastModifiedAt = $lastModifiedAt; + } + + /** + * {@inheritdoc} + */ + public function getCreatedAt(): ?string + { + return $this->createdAt; + } + + /** + * @param string $createdAt + * + * @internal + */ + public function setCreatedAt(?string $createdAt): void + { + $this->createdAt = $createdAt; + } + + /** + * {@inheritdoc} + */ + public function getRatePlan(): ?RatePlanInterface + { + return $this->ratePlan; + } + + /** + * {@inheritdoc} + */ + public function setRatePlan(?RatePlanInterface $ratePlan): void + { + $this->ratePlan = $ratePlan; + } +} diff --git a/src/Api/ApigeeX/Entity/AcceptedRatePlanInterface.php b/src/Api/ApigeeX/Entity/AcceptedRatePlanInterface.php new file mode 100755 index 00000000..35e4ecbc --- /dev/null +++ b/src/Api/ApigeeX/Entity/AcceptedRatePlanInterface.php @@ -0,0 +1,41 @@ +apiproduct; + } + + /** + * {@inheritdoc} + */ + public function setApiProduct(string $apiproduct): void + { + $this->apiproduct = $apiproduct; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/ApiProductPropertyInterface.php b/src/Api/ApigeeX/Entity/Property/ApiProductPropertyInterface.php new file mode 100755 index 00000000..d4a7cf60 --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/ApiProductPropertyInterface.php @@ -0,0 +1,35 @@ +billingPeriod; + } + + /** + * {@inheritdoc} + */ + public function setBillingPeriod(string $billingPeriod): void + { + $this->billingPeriod = $billingPeriod; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/BillingPeriodPropertyInterface.php b/src/Api/ApigeeX/Entity/Property/BillingPeriodPropertyInterface.php new file mode 100755 index 00000000..c2527e6f --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/BillingPeriodPropertyInterface.php @@ -0,0 +1,35 @@ +consumptionPricingType; + } + + /** + * {@inheritdoc} + */ + public function setConsumptionPricingType(string $consumptionPricingType): void + { + $this->consumptionPricingType = $consumptionPricingType; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/ConsumptionPricingTypePropertyInterface.php b/src/Api/ApigeeX/Entity/Property/ConsumptionPricingTypePropertyInterface.php new file mode 100755 index 00000000..56711d70 --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/ConsumptionPricingTypePropertyInterface.php @@ -0,0 +1,35 @@ +currencyCode; + } + + /** + * {@inheritdoc} + */ + public function setCurrencyCode(string $currencyCode): void + { + $this->currencyCode = $currencyCode; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/CurrencyCodePropertyInterface.php b/src/Api/ApigeeX/Entity/Property/CurrencyCodePropertyInterface.php new file mode 100755 index 00000000..7d3c9d1b --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/CurrencyCodePropertyInterface.php @@ -0,0 +1,35 @@ +endTime; + } + + /** + * {@inheritdoc} + */ + public function setEndTime(string $endTime): void + { + $this->endTime = $endTime; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/EndTimePropertyInterface.php b/src/Api/ApigeeX/Entity/Property/EndTimePropertyInterface.php new file mode 100755 index 00000000..c31304bb --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/EndTimePropertyInterface.php @@ -0,0 +1,32 @@ +fixedFeeFrequency; + } + + /** + * {@inheritdoc} + */ + public function setFixedFeeFrequency(int $fixedFeeFrequency): void + { + $this->fixedFeeFrequency = $fixedFeeFrequency; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/FixedFeeFrequencyPropertyInterface.php b/src/Api/ApigeeX/Entity/Property/FixedFeeFrequencyPropertyInterface.php new file mode 100755 index 00000000..309719c7 --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/FixedFeeFrequencyPropertyInterface.php @@ -0,0 +1,35 @@ +nanos ?? 0; + + return $nanos * pow(10, -9); + } + + /** + * {@inheritdoc} + */ + public function setNanos(int $nanos): void + { + $this->nanos = $nanos; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/NanosPropertyInterface.php b/src/Api/ApigeeX/Entity/Property/NanosPropertyInterface.php new file mode 100755 index 00000000..a485dc3e --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/NanosPropertyInterface.php @@ -0,0 +1,35 @@ +paymentFundingModel; + } + + /** + * {@inheritdoc} + */ + public function setPaymentFundingModel(string $paymentFundingModel): void + { + $this->paymentFundingModel = $paymentFundingModel; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/PaymentFundingModelPropertyInterface.php b/src/Api/ApigeeX/Entity/Property/PaymentFundingModelPropertyInterface.php new file mode 100755 index 00000000..5569ec25 --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/PaymentFundingModelPropertyInterface.php @@ -0,0 +1,35 @@ +revenueShareType; + } + + /** + * {@inheritdoc} + */ + public function setRevenueShareType(string $revenueShareType): void + { + $this->revenueShareType = $revenueShareType; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/RevenueShareTypePropertyInterface.php b/src/Api/ApigeeX/Entity/Property/RevenueShareTypePropertyInterface.php new file mode 100755 index 00000000..75b5624f --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/RevenueShareTypePropertyInterface.php @@ -0,0 +1,35 @@ +startTime; + } + + /** + * {@inheritdoc} + */ + public function setStartTime(string $startTime): void + { + $this->startTime = $startTime; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/StartTimePropertyInterface.php b/src/Api/ApigeeX/Entity/Property/StartTimePropertyInterface.php new file mode 100755 index 00000000..9d05db24 --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/StartTimePropertyInterface.php @@ -0,0 +1,32 @@ +units; + } + + /** + * {@inheritdoc} + */ + public function setUnits(string $units): void + { + $this->units = $units; + } +} diff --git a/src/Api/ApigeeX/Entity/Property/UnitsPropertyInterface.php b/src/Api/ApigeeX/Entity/Property/UnitsPropertyInterface.php new file mode 100755 index 00000000..13d44f6f --- /dev/null +++ b/src/Api/ApigeeX/Entity/Property/UnitsPropertyInterface.php @@ -0,0 +1,35 @@ +package; + } + + /** + * {@inheritdoc} + */ + public function setPackage(ApiProductInterface $package): void + { + $this->package = $package; + } + + /** + * {@inheritdoc} + */ + public function getRatePlanxFee(): array + { + return $this->ratePlanXFee; + } + + /** + * {@inheritdoc} + */ + public function setRatePlanxFee(RatePlanXFee ...$ratePlanXFee): void + { + $this->ratePlanXFee = $ratePlanXFee; + } + + /** + * {@inheritdoc} + */ + public function getFixedRecurringFee(): array + { + return $this->fixedRecurringFee; + } + + /** + * {@inheritdoc} + */ + public function setFixedRecurringFee(FixedRecurringFee ...$fixedRecurringFee): void + { + $this->fixedRecurringFee = $fixedRecurringFee; + } + + /** + * {@inheritdoc} + */ + public function getConsumptionPricingRates(): array + { + return $this->consumptionPricingRates; + } + + /** + * {@inheritdoc} + */ + public function setConsumptionPricingRates(ConsumptionPricingRate ...$consumptionPricingRates): void + { + $this->consumptionPricingRates = $consumptionPricingRates; + } + + /** + * {@inheritdoc} + */ + public function getRevenueShareRates(): array + { + return $this->revenueShareRates; + } + + /** + * {@inheritdoc} + */ + public function setRevenueShareRates(RevenueShareRates ...$revenueShareRates): void + { + $this->revenueShareRates = $revenueShareRates; + } +} diff --git a/src/Api/ApigeeX/Entity/RatePlanInterface.php b/src/Api/ApigeeX/Entity/RatePlanInterface.php new file mode 100755 index 00000000..177144a7 --- /dev/null +++ b/src/Api/ApigeeX/Entity/RatePlanInterface.php @@ -0,0 +1,107 @@ + 'RatePlanXFee', + 'fixedRecurringFee' => 'FixedRecurringFee', + ]; + + return $mapping; + } +} diff --git a/src/Api/ApigeeX/Normalizer/AcceptedRatePlanNormalizer.php b/src/Api/ApigeeX/Normalizer/AcceptedRatePlanNormalizer.php new file mode 100755 index 00000000..daaf8bdd --- /dev/null +++ b/src/Api/ApigeeX/Normalizer/AcceptedRatePlanNormalizer.php @@ -0,0 +1,51 @@ + $data) { + $normalized['product'][$id] = (object) ['id' => $data->id]; + } + + return (object) $normalized; + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return $data instanceof ApiProductInterface; + } +} diff --git a/src/Api/ApigeeX/Normalizer/RatePlanNormalizer.php b/src/Api/ApigeeX/Normalizer/RatePlanNormalizer.php new file mode 100755 index 00000000..1773a026 --- /dev/null +++ b/src/Api/ApigeeX/Normalizer/RatePlanNormalizer.php @@ -0,0 +1,83 @@ +getPackage()) { + throw new UninitializedPropertyException($object, 'package', 'Apigee\Edge\Api\ApigeeX\Entity\ApiProductInterface'); + } + + if (null === $object->getPackage()->getOrganization()) { + throw new UninitializedPropertyException($object->getPackage(), 'organization', 'Apigee\Edge\Api\Monetization\Entity\OrganizationProfileInterface'); + } + + //$this->fixTimeZoneOnNormalization($object, $normalized, $object->getPackage()->getOrganization()->getTimezone()); + + return $normalized; + } + + /** + * {@inheritDoc} + */ + public function supportsNormalization($data, $format = null) + { + return $data instanceof RatePlanInterface; + } +} diff --git a/src/Api/ApigeeX/Normalizer/RatePlanNormalizerFactory.php b/src/Api/ApigeeX/Normalizer/RatePlanNormalizerFactory.php new file mode 100755 index 00000000..7307b0cb --- /dev/null +++ b/src/Api/ApigeeX/Normalizer/RatePlanNormalizerFactory.php @@ -0,0 +1,96 @@ +normalizers = array_merge($normalizers, [ + new StandardRatePlanNormalizer(), + new DeveloperRatePlanNormalizer(), + new CompanyRatePlanNormalizer(), + new DeveloperCategoryRatePlanNormalizer(), + ]); + } + + /** + * {@inheritdoc} + * + * @psalm-suppress InvalidNullableReturnType - There are going to be at + * least one normalizer always that can normalize data here. + */ + public function normalize($object, $format = null, array $context = []) + { + foreach ($this->normalizers as $normalizer) { + // Return the result from the first denormalizer that can + // denormalize this. + if ($normalizer->supportsNormalization($object, $format)) { + return $normalizer->normalize($object, $format, $context); + } + } + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + foreach ($this->normalizers as $denormalizer) { + if ($denormalizer->supportsNormalization($data, $format)) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function setSerializer(SerializerInterface $serializer): void + { + $this->traitSetSerializer($serializer); + foreach ($this->normalizers as $denormalizer) { + if ($denormalizer instanceof SerializerAwareInterface) { + $denormalizer->setSerializer($serializer); + } + } + } +} diff --git a/src/Api/ApigeeX/Normalizer/RatePlanRateNormalizer.php b/src/Api/ApigeeX/Normalizer/RatePlanRateNormalizer.php new file mode 100755 index 00000000..e2626f1c --- /dev/null +++ b/src/Api/ApigeeX/Normalizer/RatePlanRateNormalizer.php @@ -0,0 +1,53 @@ +type = RatePlanRate::TYPE_REVSHARE; + } else { + $normalized->type = RatePlanRate::TYPE_RATECARD; + } + + return $normalized; + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return $data instanceof RatePlanRate; + } +} diff --git a/src/Api/ApigeeX/Normalizer/StandardRatePlanNormalizer.php b/src/Api/ApigeeX/Normalizer/StandardRatePlanNormalizer.php new file mode 100755 index 00000000..dda8754f --- /dev/null +++ b/src/Api/ApigeeX/Normalizer/StandardRatePlanNormalizer.php @@ -0,0 +1,48 @@ +type = RatePlanInterface::TYPE_STANDARD; + + return $normalized; + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return $data instanceof StandardRatePlanInterface; + } +} diff --git a/src/Api/ApigeeX/Serializer/AcceptedRatePlanSerializer.php b/src/Api/ApigeeX/Serializer/AcceptedRatePlanSerializer.php new file mode 100755 index 00000000..82dedb96 --- /dev/null +++ b/src/Api/ApigeeX/Serializer/AcceptedRatePlanSerializer.php @@ -0,0 +1,50 @@ +end; + } + + /** + * @param string $end + */ + public function setEnd(string $end): void + { + $this->end = $end; + } + + /** + * @return string|null + */ + public function getStart(): ?string + { + return $this->start; + } + + /** + * @param string $start + */ + public function setStart(string $start): void + { + $this->start = $start; + } + + /** + * @return \Apigee\Edge\Api\ApigeeX\Structure\Fee|null + */ + public function getFee(): ?Fee + { + return $this->fee; + } + + /** + * @param \Apigee\Edge\Api\ApigeeX\Structure\Fee $fee + */ + public function setFee(Fee $fee): void + { + $this->fee = $fee; + } +} diff --git a/src/Api/ApigeeX/Structure/Fee.php b/src/Api/ApigeeX/Structure/Fee.php new file mode 100755 index 00000000..e50e9d2d --- /dev/null +++ b/src/Api/ApigeeX/Structure/Fee.php @@ -0,0 +1,36 @@ +end; + } + + /** + * @param string $end + */ + public function setEnd(string $end): void + { + $this->end = $end; + } + + /** + * @return string|null + */ + public function getStart(): ?string + { + return $this->start; + } + + /** + * @param string $start + */ + public function setStart(string $start): void + { + $this->start = $start; + } + + /** + * @return float|null + */ + public function getSharePercentage(): ?float + { + return $this->sharePercentage; + } + + /** + * @param float $sharePercentage + */ + public function setSharePercentage(float $sharePercentage): void + { + $this->sharePercentage = $sharePercentage; + } +} diff --git a/src/Api/Monetization/Normalizer/EntityNormalizer.php b/src/Api/Monetization/Normalizer/EntityNormalizer.php index 01081dc4..ade03680 100644 --- a/src/Api/Monetization/Normalizer/EntityNormalizer.php +++ b/src/Api/Monetization/Normalizer/EntityNormalizer.php @@ -57,7 +57,7 @@ public function __construct(?ClassMetadataFactoryInterface $classMetadataFactory } /** - * @inheritdoc + * {@inheritdoc} * * @psalm-suppress InvalidReturnType stdClass is also an object. */ @@ -71,7 +71,11 @@ public function normalize($object, $format = null, array $context = []) foreach ($entityReferenceProperties as $entityProperty => $normalizedProperty) { // Ensure we do not send the complete referenced entity object // only the referenced entity id. - if (isset($normalized[$normalizedProperty]->id)) { + if (isset($normalized[$normalizedProperty]->apiProduct)) { + $normalized = [ + 'apiproduct' => $normalized[$normalizedProperty]->apiProduct, + ]; + } elseif (isset($normalized[$normalizedProperty]->id)) { $normalized[$normalizedProperty] = [ 'id' => $normalized[$normalizedProperty]->id, ]; diff --git a/src/Controller/AbstractEntityController.php b/src/Controller/AbstractEntityController.php index 9f49dd90..d03d5a99 100644 --- a/src/Controller/AbstractEntityController.php +++ b/src/Controller/AbstractEntityController.php @@ -54,7 +54,7 @@ public function __construct(ClientInterface $client, ?EntitySerializerInterface } /** - * @inheritdoc + * {@inheritdoc} */ protected function getEntityEndpointUri(string $entityId): UriInterface { @@ -64,7 +64,17 @@ protected function getEntityEndpointUri(string $entityId): UriInterface } /** - * @inheritDoc + * {@inheritdoc} + */ + protected function getEntityCancelEndpointUri(string $entityId): UriInterface + { + $encoded = $entityId; + + return $this->getBaseEndpointUri()->withPath("{$this->getBaseEndpointUri()}/{$encoded}:expire"); + } + + /** + * {@inheritdoc} */ protected function getEntitySerializer(): EntitySerializerInterface { diff --git a/src/Controller/EntityListingControllerTrait.php b/src/Controller/EntityListingControllerTrait.php index bfebdc10..f095c623 100644 --- a/src/Controller/EntityListingControllerTrait.php +++ b/src/Controller/EntityListingControllerTrait.php @@ -44,6 +44,10 @@ protected function responseArrayToArrayOfEntities(array $responseArray, string $ $entities = []; foreach ($responseArray as $item) { + //Adding id for ApigeeX. + if (!isset($item->id)) { + $item->id = $item->name ?? null; + } /** @var \Apigee\Edge\Entity\EntityInterface $tmp */ $tmp = $this->getEntitySerializer()->denormalize($item, $this->getEntityClass()); $entities[$tmp->{$keyGetter}()] = $tmp; From 2087b07553e43e096b3497a9afcccbf9210577be Mon Sep 17 00:00:00 2001 From: phdhiren <71828912+phdhiren@users.noreply.github.com> Date: Tue, 20 Apr 2021 04:03:39 +0530 Subject: [PATCH 6/7] Bump version to 2.0.7 and changelog (#137) * Updated client version in ClientInterface 2.0.7 * Updated changelog for 2.0.7. * Updated changelog for 2.0.7. * Updated changelog for 2.0.7. --- CHANGELOG.md | 7 +++++++ src/ClientInterface.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c6efbfc..a5b3278e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## [2.0.7](https://github.com/apigee/apigee-client-php/milestone/6?closed=1) +* Added support for Apigee X connections (New Feature) +API providers can now connect their Drupal 8/9 developer portals to Apigee X organizations. API providers using Apigee X with Monetization enabled can now leverage monetization features in their Drupal developer portals. For more information, see [Overview of Apigee monetization](https://cloud.google.com/apigee/docs/api-platform/monetization/overview) and the [Apigee Monetization Drupal module documentation](https://www.drupal.org/docs/contributed-modules/apigee-monetization). + +* [#105](https://github.com/apigee/apigee-client-php/pull/123) Unable to retrieve analytics data on developer app analytics page for hybrid orgs. +* [#108](https://github.com/apigee/apigee-client-php/pull/125) Notice in recent message logs if description is empty after creating app in Apigee hybrid. + ## [2.0.6](https://github.com/apigee/apigee-client-php/milestone/5?closed=1) * Dropped support of HTTPlug 1.x libraries (HTTPlug, Client Common and Guzzle 6 adapter). * Added support for GCE Service Account Authentication. diff --git a/src/ClientInterface.php b/src/ClientInterface.php index 7971740c..d9393d0e 100644 --- a/src/ClientInterface.php +++ b/src/ClientInterface.php @@ -44,7 +44,7 @@ interface ClientInterface extends HttpClient */ public const HYBRID_ENDPOINT = 'https://apigee.googleapis.com/v1'; - public const VERSION = '2.0.6'; + public const VERSION = '2.0.7'; /** * Allows access to the last request, response and exception. From 51300f696e77e9806696cebe53fff72b4e51ab8d Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Sat, 24 Apr 2021 01:40:15 +0530 Subject: [PATCH 7/7] ApiResponseException class throwing error on returning string response #138 (#139) * Fix ApiResponseException class showing warning #138 * Travis fix --- src/Exception/ApiResponseException.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Exception/ApiResponseException.php b/src/Exception/ApiResponseException.php index 2888d865..16908a21 100644 --- a/src/Exception/ApiResponseException.php +++ b/src/Exception/ApiResponseException.php @@ -61,7 +61,7 @@ public function __construct( } /** - * @inheritdoc + * {@inheritdoc} */ public function __toString() { @@ -111,6 +111,8 @@ private function parseErrorResponse(ResponseInterface $response): array $contentTypeHeader = $response->getHeaderLine('Content-Type'); if ($contentTypeHeader && false !== strpos($contentTypeHeader, 'application/json')) { $array = json_decode((string) $response->getBody(), true); + $array = is_array($array) ? $array : (array) $array; + if (JSON_ERROR_NONE === json_last_error()) { if (array_key_exists('fault', $array)) { $error['message'] = $array['fault']['faultstring'] ?? null;