Skip to content
This repository was archived by the owner on Dec 19, 2019. It is now read-only.

Create customer account functionality #254

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions app/code/Magento/CustomerGraphQl/Model/Customer/CreateAccount.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace Magento\CustomerGraphQl\Model\Customer;

use Magento\Customer\Api\AccountManagementInterface;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Customer\Api\Data\CustomerInterfaceFactory;
use Magento\Framework\Api\DataObjectHelper;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Store\Model\StoreManagerInterface;

/**
* Class CreateAccount creates new customer account
*/
class CreateAccount
{
/**
* @var DataObjectHelper
*/
private $dataObjectHelper;

/**
* @var CustomerInterfaceFactory
*/
private $customerFactory;

/**
* @var AccountManagementInterface
*/
private $accountManagement;

/**
* @var StoreManagerInterface
*/
private $storeManager;

/**
* @param DataObjectHelper $dataObjectHelper
* @param CustomerInterfaceFactory $customerFactory
* @param StoreManagerInterface $storeManager
* @param AccountManagementInterface $accountManagement
*/
public function __construct(
DataObjectHelper $dataObjectHelper,
CustomerInterfaceFactory $customerFactory,
StoreManagerInterface $storeManager,
AccountManagementInterface $accountManagement
) {
$this->dataObjectHelper = $dataObjectHelper;
$this->customerFactory = $customerFactory;
$this->accountManagement = $accountManagement;
$this->storeManager = $storeManager;
}

/**
* @param array $args
* @return CustomerInterface
* @throws LocalizedException
* @throws NoSuchEntityException
*/
public function execute($args)
{
$customerDataObject = $this->customerFactory->create();
$this->dataObjectHelper->populateWithArray(
$customerDataObject,
$args['input'],
CustomerInterface::class
);
$store = $this->storeManager->getStore();
$customerDataObject->setWebsiteId($store->getWebsiteId());
$customerDataObject->setStoreId($store->getId());

$password = array_key_exists('password', $args['input']) ? $args['input']['password'] : null;

return $this->accountManagement->createAccount($customerDataObject, $password);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Magento\CustomerGraphQl\Model\Customer;

use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
use Magento\Authorization\Model\UserContextInterface;

/**
* Set up user context after creating new customer account
*/
class SetUpUserContext
{
/**
* @param ContextInterface $context
* @param CustomerInterface $customer
*/
public function execute(ContextInterface $context, CustomerInterface $customer)
{
$context->setUserId((int)$customer->getId());
$context->setUserType(UserContextInterface::USER_TYPE_CUSTOMER);
}
}
95 changes: 95 additions & 0 deletions app/code/Magento/CustomerGraphQl/Model/Resolver/CreateCustomer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CustomerGraphQl\Model\Resolver;

use Magento\CustomerGraphQl\Model\Customer\ChangeSubscriptionStatus;
use Magento\CustomerGraphQl\Model\Customer\CreateAccount;
use Magento\CustomerGraphQl\Model\Customer\CustomerDataProvider;
use Magento\CustomerGraphQl\Model\Customer\SetUpUserContext;
use Magento\Framework\Exception\State\InputMismatchException;
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\Framework\Validator\Exception as ValidatorException;

/**
* Create customer account resolver
*/
class CreateCustomer implements ResolverInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to split this class (an example is in other resolvers of this module)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to create dockblock for all of classes

{
/**
* @var CustomerDataProvider
*/
private $customerDataProvider;

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed rmpty line

* @var ChangeSubscriptionStatus
*/
private $changeSubscriptionStatus;

/**
* @var CreateAccount
*/
private $createAccount;

/**
* @var SetUpUserContext
*/
private $setUpUserContext;

/**
* @param CustomerDataProvider $customerDataProvider
* @param ChangeSubscriptionStatus $changeSubscriptionStatus
* @param SetUpUserContext $setUpUserContext
* @param CreateAccount $createAccount
*/
public function __construct(
CustomerDataProvider $customerDataProvider,
ChangeSubscriptionStatus $changeSubscriptionStatus,
SetUpUserContext $setUpUserContext,
CreateAccount $createAccount
) {
$this->customerDataProvider = $customerDataProvider;
$this->changeSubscriptionStatus = $changeSubscriptionStatus;
$this->createAccount = $createAccount;
$this->setUpUserContext = $setUpUserContext;
}

/**
* @inheritdoc
*/
public function resolve(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use inheritdoc

Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) {
if (!isset($args['input']) || !is_array($args['input']) || empty($args['input'])) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to have more smarty validation (based on is_required values of Customer EAV attributes)

Copy link
Contributor Author

@Stepa4man Stepa4man Dec 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got it from the current \Magento\CustomerGraphQl\Model\Resolver\UpdateCustomer implementation. Is it ok for updating but not ok for creation?

Just question to think. We can have attribute requirement changed between account creation and account updating. So it also needs to be validated in customer update.

My implementation checks which fields are required

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magento\CustomerGraphQl\Model\Resolver\UpdateCustomer does not contain any validation related to settings in admin panel (there is only one rule need to provide password if you change email)

throw new GraphQlInputException(__('"input" value should be specified'));
}
try {
$customer = $this->createAccount->execute($args);
$customerId = (int)$customer->getId();
$this->setUpUserContext->execute($context, $customer);
if (array_key_exists('is_subscribed', $args['input'])) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls, reuse \Magento\CustomerGraphQl\Model\Customer\ChangeSubscriptionStatus

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if ($args['input']['is_subscribed']) {
$this->changeSubscriptionStatus->execute($customerId, true);
}
}
$data = $this->customerDataProvider->getCustomerById($customerId);
} catch (ValidatorException $e) {
throw new GraphQlInputException(__($e->getMessage()));
} catch (InputMismatchException $e) {
throw new GraphQlInputException(__($e->getMessage()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to highlight to client all of possible errors

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

}

return ['customer' => $data];
}
}
23 changes: 15 additions & 8 deletions app/code/Magento/CustomerGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,30 @@ type Query {
type Mutation {
generateCustomerToken(email: String!, password: String!): CustomerToken @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\GenerateCustomerToken") @doc(description:"Retrieve the customer token")
changeCustomerPassword(currentPassword: String!, newPassword: String!): Customer @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\ChangePassword") @doc(description:"Changes the password for the logged-in customer")
updateCustomer (input: UpdateCustomerInput!): UpdateCustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomer") @doc(description:"Update the customer's personal information")
createCustomer (input: CustomerInput!): CustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\CreateCustomer") @doc(description:"Create customer account")
updateCustomer (input: CustomerInput!): CustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomer") @doc(description:"Update the customer's personal information")
revokeCustomerToken: RevokeCustomerTokenOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\RevokeCustomerToken") @doc(description:"Revoke the customer token")
}

type CustomerToken {
token: String @doc(description: "The customer token")
}

input UpdateCustomerInput {
firstname: String
lastname: String
email: String
password: String
is_subscribed: Boolean
input CustomerInput {
prefix: String @doc(description: "An honorific, such as Dr., Mr., or Mrs.")
firstname: String @doc(description: "The customer's first name")
middlename: String @doc(description: "The customer's middle name")
lastname: String @doc(description: "The customer's family name")
suffix: String @doc(description: "A value such as Sr., Jr., or III")
email: String @doc(description: "The customer's email address. Required")
dob: String @doc(description: "The customer's date of birth")
taxvat: String @doc(description: "The customer's Tax/VAT number (for corporate customers)")
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")
}

type UpdateCustomerOutput {
type CustomerOutput {
customer: Customer!
}

Expand Down
Loading