Skip to content

Commit

Permalink
Merge pull request #9311 from magento-lynx/2.4.8-graphql-api-enhancem…
Browse files Browse the repository at this point in the history
…ents
  • Loading branch information
svera authored Nov 15, 2024
2 parents 651928c + 3b194c4 commit 0ba9eef
Show file tree
Hide file tree
Showing 49 changed files with 3,116 additions and 607 deletions.
225 changes: 225 additions & 0 deletions app/code/Magento/Customer/Test/Fixture/CustomerWithAddresses.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
<?php
/**
* Copyright 2024 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\Customer\Test\Fixture;

use Magento\Customer\Api\AccountManagementInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Api\Data\AddressInterface;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Customer\Model\CustomerRegistry;
use Magento\Framework\DataObject;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\TestFramework\Fixture\Api\DataMerger;
use Magento\TestFramework\Fixture\Api\ServiceFactory;
use Magento\TestFramework\Fixture\Data\ProcessorInterface;
use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface;

/**
* Data fixture for customer with multiple addresses
*/
class CustomerWithAddresses implements RevertibleDataFixtureInterface
{
private const DEFAULT_DATA_ADDRESS = [
[
AddressInterface::ID => null,
AddressInterface::CUSTOMER_ID => null,
AddressInterface::REGION => 'California',
AddressInterface::REGION_ID => '12',
AddressInterface::COUNTRY_ID => 'US',
AddressInterface::STREET => ['%street_number% Test Street%uniqid%'],
AddressInterface::COMPANY => null,
AddressInterface::TELEPHONE => '1234567893',
AddressInterface::FAX => null,
AddressInterface::POSTCODE => '02108',
AddressInterface::CITY => 'Boston',
AddressInterface::FIRSTNAME => 'Firstname%uniqid%',
AddressInterface::LASTNAME => 'Lastname%uniqid%',
AddressInterface::MIDDLENAME => null,
AddressInterface::PREFIX => null,
AddressInterface::SUFFIX => null,
AddressInterface::VAT_ID => null,
AddressInterface::DEFAULT_BILLING => true,
AddressInterface::DEFAULT_SHIPPING => true,
AddressInterface::CUSTOM_ATTRIBUTES => [],
AddressInterface::EXTENSION_ATTRIBUTES_KEY => [],
],
[
AddressInterface::ID => null,
AddressInterface::CUSTOMER_ID => null,
AddressInterface::REGION => 'California',
AddressInterface::REGION_ID => '12',
AddressInterface::COUNTRY_ID => 'US',
AddressInterface::STREET => ['%street_number% Sunset Boulevard%uniqid%'],
AddressInterface::COMPANY => null,
AddressInterface::TELEPHONE => '0987654321',
AddressInterface::FAX => null,
AddressInterface::POSTCODE => '90001',
AddressInterface::CITY => 'Los Angeles',
AddressInterface::FIRSTNAME => 'Firstname%uniqid%',
AddressInterface::LASTNAME => 'Lastname%uniqid%',
AddressInterface::MIDDLENAME => null,
AddressInterface::PREFIX => null,
AddressInterface::SUFFIX => null,
AddressInterface::VAT_ID => null,
AddressInterface::DEFAULT_BILLING => false,
AddressInterface::DEFAULT_SHIPPING => false,
AddressInterface::CUSTOM_ATTRIBUTES => [],
AddressInterface::EXTENSION_ATTRIBUTES_KEY => [],
],
[
AddressInterface::ID => null,
AddressInterface::CUSTOMER_ID => null,
AddressInterface::REGION => 'New York',
AddressInterface::REGION_ID => '43',
AddressInterface::COUNTRY_ID => 'US',
AddressInterface::STREET => ['%street_number% 5th Avenue%uniqid%'],
AddressInterface::COMPANY => null,
AddressInterface::TELEPHONE => '1112223333',
AddressInterface::FAX => null,
AddressInterface::POSTCODE => '10001',
AddressInterface::CITY => 'New York City',
AddressInterface::FIRSTNAME => 'Firstname%uniqid%',
AddressInterface::LASTNAME => 'Lastname%uniqid%',
AddressInterface::MIDDLENAME => null,
AddressInterface::PREFIX => null,
AddressInterface::SUFFIX => null,
AddressInterface::VAT_ID => null,
AddressInterface::DEFAULT_BILLING => false,
AddressInterface::DEFAULT_SHIPPING => false,
AddressInterface::CUSTOM_ATTRIBUTES => [],
AddressInterface::EXTENSION_ATTRIBUTES_KEY => [],
]
];

private const DEFAULT_DATA = [
'password' => 'password',
CustomerInterface::ID => null,
CustomerInterface::CREATED_AT => null,
CustomerInterface::CONFIRMATION => null,
CustomerInterface::UPDATED_AT => null,
CustomerInterface::DOB => null,
CustomerInterface::CREATED_IN => null,
CustomerInterface::EMAIL => 'customer%uniqid%@mail.com',
CustomerInterface::FIRSTNAME => 'Firstname%uniqid%',
CustomerInterface::GROUP_ID => null,
CustomerInterface::GENDER => null,
CustomerInterface::LASTNAME => 'Lastname%uniqid%',
CustomerInterface::MIDDLENAME => null,
CustomerInterface::PREFIX => null,
CustomerInterface::SUFFIX => null,
CustomerInterface::STORE_ID => null,
CustomerInterface::TAXVAT => null,
CustomerInterface::WEBSITE_ID => null,
CustomerInterface::DEFAULT_SHIPPING => null,
CustomerInterface::DEFAULT_BILLING => null,
CustomerInterface::DISABLE_AUTO_GROUP_CHANGE => null,
CustomerInterface::KEY_ADDRESSES => [],
CustomerInterface::CUSTOM_ATTRIBUTES => [],
CustomerInterface::EXTENSION_ATTRIBUTES_KEY => [],
];

/**
* CustomerWithAddresses Constructor
*
* @param ServiceFactory $serviceFactory
* @param AccountManagementInterface $accountManagement
* @param CustomerRegistry $customerRegistry
* @param ProcessorInterface $dataProcessor
* @param DataMerger $dataMerger
*/
public function __construct(
private readonly ServiceFactory $serviceFactory,
private readonly AccountManagementInterface $accountManagement,
private readonly CustomerRegistry $customerRegistry,
private readonly DataMerger $dataMerger,
private readonly ProcessorInterface $dataProcessor
) {
}

/**
* Apply the changes for the fixture
*
* @param array $data
* @return DataObject|null
* @throws NoSuchEntityException
*/
public function apply(array $data = []): ?DataObject
{
$customerSave = $this->serviceFactory->create(CustomerRepositoryInterface::class, 'save');
$data = $this->prepareCustomerData($data);
$passwordHash = $this->accountManagement->getPasswordHash($data['password']);
unset($data['password']);

$customerSave->execute(
[
'customer' => $data,
'passwordHash' => $passwordHash
]
);

return $this->customerRegistry->retrieveByEmail($data['email'], $data['website_id']);
}

/**
* Revert the test customer creation
*
* @param DataObject $data
* @return void
*/
public function revert(DataObject $data): void
{
$data->setCustomerId($data->getId());
$customerService = $this->serviceFactory->create(CustomerRepositoryInterface::class, 'deleteById');

$customerService->execute(
[
'customerId' => $data->getId()
]
);
}

/**
* Prepare customer's data
*
* @param array $data
* @return array
*/
private function prepareCustomerData(array $data): array
{
$data = $this->dataMerger->merge(self::DEFAULT_DATA, $data);
$data[CustomerInterface::KEY_ADDRESSES] = $this->prepareAddresses($data[CustomerInterface::KEY_ADDRESSES]);

return $this->dataProcessor->process($this, $data);
}

/**
* Prepare customer's addresses
*
* @param array $data
* @return array
*/
private function prepareAddresses(array $data): array
{
$addressesData = [];
$default = self::DEFAULT_DATA_ADDRESS;
$streetNumber = 123;
foreach ($default as $address) {
if ($data) {
$address = $this->dataMerger->merge($default, $address);
}
$placeholders = ['%street_number%' => $streetNumber++];
$address[AddressInterface::STREET] = array_map(
fn ($str) => strtr($str, $placeholders),
$address[AddressInterface::STREET]
);
$addressesData[] = $address;
}

return $addressesData;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
/**
* Copyright 2024 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\CustomerGraphQl\Model\Formatter;

use Magento\Customer\Api\Data\AddressSearchResultsInterface;
use Magento\CustomerGraphQl\Model\Customer\Address\ExtractCustomerAddressData;

class CustomerAddresses
{
/**
* CustomerAddresses Constructor
*
* @param ExtractCustomerAddressData $extractCustomerAddressData
*/
public function __construct(
private readonly ExtractCustomerAddressData $extractCustomerAddressData,
) {
}

/**
* Format customer addressesV2
*
* @param AddressSearchResultsInterface $searchResult
* @return array
*/
public function format(AddressSearchResultsInterface $searchResult): array
{
$addressArray = [];
foreach ($searchResult->getItems() as $address) {
$addressArray[] = $this->extractCustomerAddressData->execute($address);
}

return [
'total_count' => $searchResult->getTotalCount(),
'items' => $addressArray,
'page_info' => [
'page_size' => $searchResult->getSearchCriteria()->getPageSize(),
'current_page' => $searchResult->getSearchCriteria()->getCurrentPage(),
'total_pages' => (int)ceil($searchResult->getTotalCount()
/ (int)$searchResult->getSearchCriteria()->getPageSize()),
]
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php
/**
* Copyright 2024 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\CustomerGraphQl\Model\Resolver;

use Magento\Customer\Api\AddressRepositoryInterface;
use Magento\Customer\Model\Customer;
use Magento\CustomerGraphQl\Model\ValidateAddressRequest;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Exception\InputException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\CustomerGraphQl\Model\Formatter\CustomerAddresses as AddressFormatter;

/**
* Provides data for customer.addressesV2 with pagination
*/
class CustomerAddressesV2 implements ResolverInterface
{
/**
* CustomerAddressesV2 Constructor
*
* @param AddressRepositoryInterface $addressRepository
* @param SearchCriteriaBuilder $searchCriteriaBuilder
* @param AddressFormatter $addressesFormatter
* @param ValidateAddressRequest $validateAddressRequest
*/
public function __construct(
private readonly AddressRepositoryInterface $addressRepository,
private readonly SearchCriteriaBuilder $searchCriteriaBuilder,
private readonly AddressFormatter $addressesFormatter,
private readonly ValidateAddressRequest $validateAddressRequest
) {
}

/**
* @inheritDoc
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
): array {
$this->validateAddressRequest->execute($value, $args);

/** @var Customer $customer */
$customer = $value['model'];

try {
$this->searchCriteriaBuilder->addFilter('parent_id', (int)$customer->getId());
$this->searchCriteriaBuilder->setCurrentPage($args['currentPage']);
$this->searchCriteriaBuilder->setPageSize($args['pageSize']);
$searchResult = $this->addressRepository->getList($this->searchCriteriaBuilder->create());
} catch (InputException $e) {
throw new GraphQlInputException(__($e->getMessage()));
}

return $this->addressesFormatter->format($searchResult);
}
}
38 changes: 38 additions & 0 deletions app/code/Magento/CustomerGraphQl/Model/ValidateAddressRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
/**
* Copyright 2024 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\CustomerGraphQl\Model;

use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;

class ValidateAddressRequest
{
/**
* Validate addresses Request
*
* @param array $value
* @param array $args
* @return void
* @throws GraphQlInputException
* @throws LocalizedException
*/
public function execute(array $value, array $args): void
{
if (!isset($value['model'])) {
throw new LocalizedException(__('"model" value should be specified'));
}

if ($args['pageSize'] < 1) {
throw new GraphQlInputException(__('pageSize value must be greater than 0.'));
}

if ($args['currentPage'] < 1) {
throw new GraphQlInputException(__('currentPage value must be greater than 0.'));
}
}
}
Loading

0 comments on commit 0ba9eef

Please sign in to comment.