Skip to content

Commit

Permalink
LYNX-120: Add custom_attributes to createCustomerV2 mutation (#99)
Browse files Browse the repository at this point in the history
* LYNX-120: Initial commit

* LYNX-120: Create custom attributes in createCustomerV2 mutation + test

* LYNX-120: fix test

* LYNX-120: fix test

* LYNX-120: Final implementation + tests

* LYNX-120: Refactoring

* LYNX-120: Refactoring

* LYNX-120: Refactoring

* LYNX-120: Refactoring

* LYNX-120: Refactoring; CR changes

* LYNX-120: Refactoring; CR changes

* LYNX-120: Refactoring; CR changes

* LYNX-120: Refactoring; CR changes

* LYNX-120: CR changes

* LYNX-120: CR changes

* LYNX-120: CR changes

* LYNX-120: CR changes

* LYNX-120: Fix broken tests
  • Loading branch information
bl4de authored Apr 28, 2023
1 parent 0e8655d commit a771bd8
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\Customer\Model\ResourceModel;

use Magento\Customer\Api\CustomerMetadataInterface;
Expand Down Expand Up @@ -407,8 +406,8 @@ public function getById($customerId)
* Retrieve customers which match a specified criteria.
*
* This call returns an array of objects, but detailed information about each object’s attributes might not be
* included. See https://developer.adobe.com/commerce/webapi/rest/attributes#CustomerRepositoryInterface to determine
* which call to use to get detailed information about all attributes for an object.
* included. See https://developer.adobe.com/commerce/webapi/rest/attributes#CustomerRepositoryInterface
* to determine which call to use to get detailed information about all attributes for an object.
*
* @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
* @return \Magento\Customer\Api\Data\CustomerSearchResultsInterface
Expand Down Expand Up @@ -540,6 +539,14 @@ private function prepareCustomerData(array $customerData): array
{
if (isset($customerData[CustomerInterface::CUSTOM_ATTRIBUTES])) {
foreach ($customerData[CustomerInterface::CUSTOM_ATTRIBUTES] as $attribute) {
if (empty($attribute['value'])
&& !empty($attribute['selected_options'])
&& is_array($attribute['selected_options'])
) {
$attribute['value'] = implode(',', array_map(function ($option): string {
return $option['value'] ?? '';
}, $attribute['selected_options']));
}
$customerData[$attribute['attribute_code']] = $attribute['value'];
}
unset($customerData[CustomerInterface::CUSTOM_ATTRIBUTES]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ private function createAccount(array $data, StoreInterface $store): CustomerInte
$customerDataObject,
CustomerInterface::class
);

$data = array_merge($requiredDataAttributes, $data);
$this->validateCustomerData->execute($data);
$this->dataObjectHelper->populateWithArray(
Expand Down
5 changes: 3 additions & 2 deletions app/code/Magento/CustomerGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ input CustomerAddressInput @doc(description: "Contains details about a billing o
prefix: String @doc(description: "An honorific, such as Dr., Mr., or Mrs.")
suffix: String @doc(description: "A value such as Sr., Jr., or III.")
vat_id: String @doc(description: "The customer's Tax/VAT number (for corporate customers).")
custom_attributes: [CustomerAddressAttributeInput] @doc(description: "Deprecated: Custom attributes should not be put into container.")
custom_attributes: [AttributeValueInput] @doc(description: "Deprecated: Custom attributes should not be put into container.")
}

input CustomerAddressRegionInput @doc(description: "Defines the customer's state or province.") {
Expand Down Expand Up @@ -95,6 +95,7 @@ input CustomerCreateInput @doc(description: "An input object for creating a cus
gender: Int @doc(description: "The customer's gender (Male - 1, Female - 2).")
password: String @doc(description: "The customer's password.")
is_subscribed: Boolean @doc(description: "Indicates whether the customer is subscribed to the company's newsletter.")
custom_attributes: [AttributeValueInput!] @doc(description: "The customer's custom attributes.")
}

input CustomerUpdateInput @doc(description: "An input object for updating a customer.") {
Expand Down Expand Up @@ -136,7 +137,7 @@ type Customer @doc(description: "Defines the customer name, addresses, and other
is_subscribed: Boolean @doc(description: "Indicates whether the customer is subscribed to the company's newsletter.") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\IsSubscribed")
addresses: [CustomerAddress] @doc(description: "An array containing the customer's shipping and billing addresses.") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\CustomerAddresses")
gender: Int @doc(description: "The customer's gender (Male - 1, Female - 2).")
custom_attributes: [AttributeValueInterface!]! @doc(description: "Customer's custom attributes.")
custom_attributes: [AttributeValueInterface] @doc(description: "Customer's custom attributes.")
}

type CustomerAddress @doc(description: "Contains detailed information about a customer's billing or shipping address."){
Expand Down
10 changes: 10 additions & 0 deletions app/code/Magento/EavGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ type StorefrontProperties @doc(description: "Indicates where an attribute can be
use_in_search_results_layered_navigation: Boolean @doc(description: "Indicates whether the attribute can be used in layered navigation on search results pages.")
}

input AttributeValueInput @doc(description: "Specifies the value for attribute.") {
attribute_code: String! @doc(description: "The code of the attribute.")
value: String @doc(description: "The value which should be set for the attribute")
selected_options: [AttributeInputSelectedOption!] @doc(description: "An array with selected option(s) for select or multiselect attribute")
}

input AttributeInputSelectedOption @doc(description: "Specifies selected option for dropdown or multiselect attribute value .") {
value: String! @doc(description: "The attribute option value.")
}

enum UseInLayeredNavigationOptions @doc(description: "Defines whether the attribute is filterable in layered navigation.") {
NO
FILTERABLE_WITH_RESULTS
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\GraphQl\Customer;

use Magento\TestFramework\Helper\Bootstrap;
use Magento\Customer\Api\CustomerMetadataInterface;
use Magento\TestFramework\Fixture\DataFixture;
use Magento\Customer\Test\Fixture\CustomerAttribute;
use Magento\TestFramework\TestCase\GraphQlAbstract;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Framework\Registry;

/**
* Tests for create customer (V2)
*/
class CreateCustomerV2WithCustomAttributesTest extends GraphQlAbstract
{
/**
* @var Registry
*/
private $registry;

/**
* @var CustomerRepositoryInterface
*/
private $customerRepository;

protected function setUp(): void
{
parent::setUp();

$this->registry = Bootstrap::getObjectManager()->get(Registry::class);
$this->customerRepository = Bootstrap::getObjectManager()->get(CustomerRepositoryInterface::class);
}

/**
* @throws \Exception
*/
#[
DataFixture(
CustomerAttribute::class,
[
'entity_type_id' => CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER,
'sort_order' => 1,
'attribute_code' => 'custom_attribute_one',
'attribute_set_id' => CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER,
'attribute_group_id' => 1
],
'attribute1'
),
DataFixture(
CustomerAttribute::class,
[
'entity_type_id' => CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER,
'sort_order' => 2,
'attribute_code' => 'custom_attribute_two',
'attribute_set_id' => CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER,
'attribute_group_id' => 1
],
'attribute2'
)
]
public function testCreateCustomerAccountWithCustomAttributes()
{
$query = <<<QUERY
mutation {
createCustomerV2(
input: {
firstname: "Adam"
lastname: "Smith"
email: "[email protected]"
password: "test123#"
custom_attributes: [
{
attribute_code: "custom_attribute_one",
value: "value_one"
},
{
attribute_code: "custom_attribute_two",
value: "value_two"
}
]
}
) {
customer {
firstname
lastname
email
custom_attributes {
uid
code
... on AttributeValue {
value
}
}
}
}
}
QUERY;
$response = $this->graphQlMutation($query);
$this->assertEquals(
[
'createCustomerV2' =>
[
'customer' =>
[
'firstname' => 'Adam',
'lastname' => 'Smith',
'email' => '[email protected]',
'custom_attributes' =>
[
0 =>
[
'uid' => 'Y3VzdG9tZXIvY3VzdG9tX2F0dHJpYnV0ZV9vbmU=',
'code' => 'custom_attribute_one',
'value' => 'value_one',
],
1 =>
[
'uid' => 'Y3VzdG9tZXIvY3VzdG9tX2F0dHJpYnV0ZV90d28=',
'code' => 'custom_attribute_two',
'value' => 'value_two',
],
],
],
],
],
$response
);
}

public function testCreateCustomerAccountWithNonExistingCustomAttribute()
{
$query = <<<QUERY
mutation {
createCustomerV2(
input: {
firstname: "John"
lastname: "Doe"
email: "[email protected]"
password: "test123#"
custom_attributes: [
{
attribute_code: "non_existing_custom_attribute",
value: "void"
}
]
}
) {
customer {
firstname
lastname
email
custom_attributes {
uid
code
... on AttributeValue {
value
}
}
}
}
}
QUERY;
$response = $this->graphQlMutation($query);
$this->assertEquals(
[
'createCustomerV2' =>
[
'customer' =>
[
'firstname' => 'John',
'lastname' => 'Doe',
'email' => '[email protected]',
'custom_attributes' => []
],
],
],
$response
);
}

protected function tearDown(): void
{
$email1 = '[email protected]';
$email2 = '[email protected]';
try {
$customer1 = $this->customerRepository->get($email1);
$customer2 = $this->customerRepository->get($email2);
} catch (\Exception $exception) {
return;
}

$this->registry->unregister('isSecureArea');
$this->registry->register('isSecureArea', true);
$this->customerRepository->delete($customer1);
$this->customerRepository->delete($customer2);
$this->registry->unregister('isSecureArea');
$this->registry->register('isSecureArea', false);
parent::tearDown();
}
}

0 comments on commit a771bd8

Please sign in to comment.