{"id":71572,"date":"2017-01-14T08:50:56","date_gmt":"2017-01-14T08:50:56","guid":{"rendered":"http:\/\/webkul.com\/blog\/?p=71572"},"modified":"2025-12-23T06:53:54","modified_gmt":"2025-12-23T06:53:54","slug":"magento2-service-contract","status":"publish","type":"post","link":"https:\/\/webkul.com\/blog\/magento2-service-contract\/","title":{"rendered":"Magento 2 Service Contract"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction to service contract:<\/h2>\n\n\n\n<p>In general, understanding a service contract is an agreement between the two parties, where one is the service provider, and the other is the service consumer.<\/p>\n\n\n\n<p>A service contract defines all the services that are going to be provided with some pre- and post-conditions. And it works in the same way in programming, too.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><b>What is the service contract in Magento 2?<\/b><\/h3>\n\n\n\n<p>In Magento 2 service contract is a set of classes and interfaces that provide some services that hide the business logic and also provide data integrity.<\/p>\n\n\n\n<p>So you can create modules using <a href=\"https:\/\/webkul.com\/magento-development\/\">Magento 2 service<\/a> contract layer without worrying about the Magento 2 upgrades(until any major ones).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Why Magento 2 Uses a <\/b>service contract<b>?<\/b><\/h3>\n\n\n\n<p>If you have worked on Magento 1, you should know that there was no proper way of interacting with other modules; you had to use models, collection helper classes (business logic) directly.<\/p>\n\n\n\n<p>And if you want to work on an EAV entity, you will have a lot of difficulty, but through service contracts, you can easily set, get, and manipulate data.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Benefits of using the service contract design pattern in Magento 2:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Services ensure data integrity.<\/li>\n\n\n\n<li>Very easy for third-party developers and modules to utilize the services provided in the service contract.<\/li>\n\n\n\n<li>Services can be easily converted to robust web api\u2019s.<\/li>\n\n\n\n<li>Using a service contract ensures module stability even in <a href=\"https:\/\/webkul.com\/magento-2-upgrade-services\/\">Magento 2 upgrades<\/a>.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Let&#8217;s understand how the structure works:<\/b><\/h3>\n\n\n\n<p><strong>You need to define some classes and interfaces in order to create a service contract in your module:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Data Interfaces<\/li>\n\n\n\n<li>Repositories Interface<\/li>\n\n\n\n<li>Management Interfaces<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Data Interfaces:<\/b><\/h3>\n\n\n\n<p>Data interfaces are used to maintain the integrity of the data; data interfaces define all the setters and getters for the related entity.<\/p>\n\n\n\n<p>So even if there are any changes in the model or business logic, you will always get consistent data.<\/p>\n\n\n\n<p>Data interfaces reside in VendorName\\ModuleName\\Api\\Data, so in all the modules, you can find data interfaces in Api\/Data folders.<\/p>\n\n\n\n<p>The related model needs to implement these interfaces and provide the setter, getter definitions.<\/p>\n\n\n\n<p>Let&#8217;s see the example of Magento 2 customer module Magento\\Customer\\Api\\Data\\CustomerInterface :<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;?php\n\/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n *\/\nnamespace Magento\\Customer\\Api\\Data;\n\n\/**\n * Customer entity interface for API handling.\n *\n * @api\n * @since 100.0.2\n *\/\ninterface CustomerInterface extends \\Magento\\Framework\\Api\\CustomAttributesDataInterface\n{\n    \/**#@+\n     * Constants defined for keys of the data array. Identical to the name of the getter in snake case\n     *\/\n    const ID = 'id';\n    const CONFIRMATION = 'confirmation';\n    const CREATED_AT = 'created_at';\n    const UPDATED_AT = 'updated_at';\n    const CREATED_IN = 'created_in';\n    const DOB = 'dob';\n    const EMAIL = 'email';\n    const FIRSTNAME = 'firstname';\n    const GENDER = 'gender';\n    const GROUP_ID = 'group_id';\n    const LASTNAME = 'lastname';\n    const MIDDLENAME = 'middlename';\n    const PREFIX = 'prefix';\n    const STORE_ID = 'store_id';\n    const SUFFIX = 'suffix';\n    const TAXVAT = 'taxvat';\n    const WEBSITE_ID = 'website_id';\n    const DEFAULT_BILLING = 'default_billing';\n    const DEFAULT_SHIPPING = 'default_shipping';\n    const KEY_ADDRESSES = 'addresses';\n    const DISABLE_AUTO_GROUP_CHANGE = 'disable_auto_group_change';\n    \/**#@-*\/\n\n    \/**\n     * Get customer id\n     *\n     * @return int|null\n     *\/\n    public function getId();\n\n    \/**\n     * Set customer id\n     *\n     * @param int $id\n     * @return $this\n     *\/\n    public function setId($id);\n\n    \/**\n     * Get group id\n     *\n     * @return int|null\n     *\/\n    public function getGroupId();\n\n    \/**\n     * Set group id\n     *\n     * @param int $groupId\n     * @return $this\n     *\/\n    public function setGroupId($groupId);\n\n    \/**\n     * Get default billing address id\n     *\n     * @return string|null\n     *\/\n    public function getDefaultBilling();\n\n    \/**\n     * Set default billing address id\n     *\n     * @param string $defaultBilling\n     * @return $this\n     *\/\n    public function setDefaultBilling($defaultBilling);\n\n    \/**\n     * Get default shipping address id\n     *\n     * @return string|null\n     *\/\n    public function getDefaultShipping();\n\n    \/**\n     * Set default shipping address id\n     *\n     * @param string $defaultShipping\n     * @return $this\n     *\/\n    public function setDefaultShipping($defaultShipping);\n\n    \/**\n     * Get confirmation\n     *\n     * @return string|null\n     *\/\n    public function getConfirmation();\n\n    \/**\n     * Set confirmation\n     *\n     * @param string $confirmation\n     * @return $this\n     *\/\n    public function setConfirmation($confirmation);\n\n    \/**\n     * Get created at time\n     *\n     * @return string|null\n     *\/\n    public function getCreatedAt();\n\n    \/**\n     * Set created at time\n     *\n     * @param string $createdAt\n     * @return $this\n     *\/\n    public function setCreatedAt($createdAt);\n\n    \/**\n     * Get updated at time\n     *\n     * @return string|null\n     *\/\n    public function getUpdatedAt();\n\n    \/**\n     * Set updated at time\n     *\n     * @param string $updatedAt\n     * @return $this\n     *\/\n    public function setUpdatedAt($updatedAt);\n\n    \/**\n     * Get created in area\n     *\n     * @return string|null\n     *\/\n    public function getCreatedIn();\n\n    \/**\n     * Set created in area\n     *\n     * @param string $createdIn\n     * @return $this\n     *\/\n    public function setCreatedIn($createdIn);\n\n    \/**\n     * Get date of birth\n     *\n     * @return string|null In keeping with current security and privacy best practices, be sure you are aware of any\n     * potential legal and security risks associated with the storage of customers\u2019 full date of birth\n     * (month, day, year) along with other personal identifiers (e.g., full name) before collecting or processing\n     * such data.\n     *\/\n    public function getDob();\n\n    \/**\n     * Set date of birth\n     *\n     * @param string $dob\n     * @return $this\n     *\/\n    public function setDob($dob);\n\n    \/**\n     * Get email address\n     *\n     * @return string\n     *\/\n    public function getEmail();\n\n    \/**\n     * Set email address\n     *\n     * @param string $email\n     * @return $this\n     *\/\n    public function setEmail($email);\n\n    \/**\n     * Get first name\n     *\n     * @return string\n     *\/\n    public function getFirstname();\n\n    \/**\n     * Set first name\n     *\n     * @param string $firstname\n     * @return $this\n     *\/\n    public function setFirstname($firstname);\n\n    \/**\n     * Get last name\n     *\n     * @return string\n     *\/\n    public function getLastname();\n\n    \/**\n     * Set last name\n     *\n     * @param string $lastname\n     * @return $this\n     *\/\n    public function setLastname($lastname);\n\n    \/**\n     * Get middle name\n     *\n     * @return string|null\n     *\/\n    public function getMiddlename();\n\n    \/**\n     * Set middle name\n     *\n     * @param string $middlename\n     * @return $this\n     *\/\n    public function setMiddlename($middlename);\n\n    \/**\n     * Get prefix\n     *\n     * @return string|null\n     *\/\n    public function getPrefix();\n\n    \/**\n     * Set prefix\n     *\n     * @param string $prefix\n     * @return $this\n     *\/\n    public function setPrefix($prefix);\n\n    \/**\n     * Get suffix\n     *\n     * @return string|null\n     *\/\n    public function getSuffix();\n\n    \/**\n     * Set suffix\n     *\n     * @param string $suffix\n     * @return $this\n     *\/\n    public function setSuffix($suffix);\n\n    \/**\n     * Get gender\n     *\n     * @return int|null\n     *\/\n    public function getGender();\n\n    \/**\n     * Set gender\n     *\n     * @param int $gender\n     * @return $this\n     *\/\n    public function setGender($gender);\n\n    \/**\n     * Get store id\n     *\n     * @return int|null\n     *\/\n    public function getStoreId();\n\n    \/**\n     * Set store id\n     *\n     * @param int $storeId\n     * @return $this\n     *\/\n    public function setStoreId($storeId);\n\n    \/**\n     * Get tax Vat\n     *\n     * @return string|null\n     *\/\n    public function getTaxvat();\n\n    \/**\n     * Set tax Vat\n     *\n     * @param string $taxvat\n     * @return $this\n     *\/\n    public function setTaxvat($taxvat);\n\n    \/**\n     * Get website id\n     *\n     * @return int|null\n     *\/\n    public function getWebsiteId();\n\n    \/**\n     * Set website id\n     *\n     * @param int $websiteId\n     * @return $this\n     *\/\n    public function setWebsiteId($websiteId);\n\n    \/**\n     * Get customer addresses.\n     *\n     * @return \\Magento\\Customer\\Api\\Data\\AddressInterface[]|null\n     *\/\n    public function getAddresses();\n\n    \/**\n     * Set customer addresses.\n     *\n     * @param \\Magento\\Customer\\Api\\Data\\AddressInterface[] $addresses\n     * @return $this\n     *\/\n    public function setAddresses(array $addresses = null);\n\n    \/**\n     * Get disable auto group change flag.\n     *\n     * @return int|null\n     *\/\n    public function getDisableAutoGroupChange();\n\n    \/**\n     * Set disable auto group change flag.\n     *\n     * @param int $disableAutoGroupChange\n     * @return $this\n     *\/\n    public function setDisableAutoGroupChange($disableAutoGroupChange);\n\n    \/**\n     * Retrieve existing extension attributes object or create a new one.\n     *\n     * @return \\Magento\\Customer\\Api\\Data\\CustomerExtensionInterface|null\n     *\/\n    public function getExtensionAttributes();\n\n    \/**\n     * Set an extension attributes object.\n     *\n     * @param \\Magento\\Customer\\Api\\Data\\CustomerExtensionInterface $extensionAttributes\n     * @return $this\n     *\/\n    public function setExtensionAttributes(\\Magento\\Customer\\Api\\Data\\CustomerExtensionInterface $extensionAttributes);\n}<\/pre>\n\n\n\n<p>In the above interface, you can observe several member variables along with their corresponding setters and getters, which collectively define how customer-related data can be accessed and modified.<\/p>\n\n\n\n<p><span style=\"color: #006699;\"><span style=\"font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;\"><span style=\"font-size: small;\"><b><code class=\"western\">public<\/code><\/b><\/span><\/span><\/span> <span style=\"color: #006699;\"><span style=\"font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;\"><span style=\"font-size: small;\"><b><code class=\"western\">function<\/code><\/b><\/span><\/span><\/span> <span style=\"color: #000000;\"><span style=\"font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;\"><span style=\"font-size: small;\"><code class=\"western\">getExtensionAttributes();<\/code><\/span><\/span><\/span><\/p>\n\n\n\n<p><span style=\"color: #006699;\"><span style=\"font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;\"><span style=\"font-size: small;\"><b><code class=\"western\">public<\/code><\/b><\/span><\/span><\/span> <code class=\"western\"><\/code><span style=\"color: #006699;\"><span style=\"font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;\"><span style=\"font-size: small;\"><b><code class=\"western\">function<\/code><\/b><\/span><\/span><\/span> <code class=\"western\"><\/code><span style=\"color: #000000;\"><span style=\"font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;\"><span style=\"font-size: small;\"><code class=\"western\">setExtensionAttributes(\\Magento\\Customer\\Api\\Data\\CustomerExtensionInterface <\/code><\/span><\/span><\/span><span style=\"color: #aa7700;\"><span style=\"font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;\"><span style=\"font-size: small;\"><code class=\"western\">$extensionAttributes<\/code><\/span><\/span><\/span><span style=\"color: #000000;\"><span style=\"font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;\"><span style=\"font-size: small;\"><code class=\"western\">);<\/code><\/span><\/span><\/span><\/p>\n\n\n\n<p>These methods are used to get and set extension attributes of the entity. Extension attributes are different from custom attributes as they can store complex data types.<\/p>\n\n\n\n<p>You can learn about extension attributes here:<\/p>\n\n\n\n<p id=\"breadcrumbs\"><a href=\"http:\/\/webkul.com\/blog\/add-extension-attribute-magento2\/\"><span class=\"breadcrumb_last\">HOW TO ADD EXTENSION ATTRIBUTE IN MAGENTO 2<\/span><\/a><\/p>\n\n\n\n<p><a href=\"http:\/\/devdocs.magento.com\/guides\/v2.0\/extension-dev-guide\/attributes.html\">EAV and extension attributes<\/a><\/p>\n\n\n\n<p>Using this way of defining your module resources gives you an advantage in creating the web API for the module. I have already explained how to create rest REST-based web API in my previous article:<\/p>\n\n\n\n<p id=\"breadcrumbs\"><a href=\"http:\/\/webkul.com\/blog\/magento2-custom-rest-api\/\"><span class=\"breadcrumb_last\">HOW TO CREATE REST-BASED WEB API IN MAGENTO 2<\/span><\/a><\/p>\n\n\n\n<p><strong>Now all the data interfaces are implemented and defined in the related models. Since the above example is of a customer model, let&#8217;s see its concrete version:<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;?php\n\/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n *\/\n\nnamespace Magento\\Customer\\Model;\n\nuse Magento\\Customer\\Api\\CustomerMetadataInterface;\nuse Magento\\Customer\\Api\\Data\\CustomerInterfaceFactory;\nuse Magento\\Customer\\Api\\GroupRepositoryInterface;\nuse Magento\\Customer\\Model\\Config\\Share;\nuse Magento\\Customer\\Model\\ResourceModel\\Address\\CollectionFactory;\nuse Magento\\Customer\\Model\\ResourceModel\\Customer as ResourceCustomer;\nuse Magento\\Framework\\App\\Config\\ScopeConfigInterface;\nuse Magento\\Framework\\Exception\\AuthenticationException;\nuse Magento\\Framework\\Exception\\EmailNotConfirmedException;\nuse Magento\\Framework\\Exception\\InvalidEmailOrPasswordException;\nuse Magento\\Framework\\Indexer\\StateInterface;\nuse Magento\\Framework\\Reflection\\DataObjectProcessor;\nuse Magento\\Store\\Model\\ScopeInterface;\nuse Magento\\Framework\\App\\ObjectManager;\nuse Magento\\Framework\\Math\\Random;\nuse Magento\\Framework\\Indexer\\IndexerInterface;\n\n\/**\n * Customer model\n *\n * @api\n * @method int getWebsiteId() getWebsiteId()\n * @method Customer setWebsiteId($value)\n * @method int getStoreId() getStoreId()\n * @method string getEmail() getEmail()\n * @method mixed getDisableAutoGroupChange()\n * @method Customer setDisableAutoGroupChange($value)\n * @method Customer setGroupId($value)\n * @method Customer setDefaultBilling($value)\n * @method Customer setDefaultShipping($value)\n * @method Customer setPasswordHash($string)\n * @method string getPasswordHash()\n * @method string getConfirmation()\n * @SuppressWarnings(PHPMD.ExcessivePublicCount)\n * @SuppressWarnings(PHPMD.TooManyFields)\n * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)\n * @SuppressWarnings(PHPMD.CouplingBetweenObjects)\n * @since 100.0.2\n *\/\nclass Customer extends \\Magento\\Framework\\Model\\AbstractModel\n{\n    \/**\n     * Configuration paths for email templates and identities\n     *\/\n    const XML_PATH_REGISTER_EMAIL_TEMPLATE = 'customer\/create_account\/email_template';\n\n    const XML_PATH_REGISTER_EMAIL_IDENTITY = 'customer\/create_account\/email_identity';\n\n    const XML_PATH_REMIND_EMAIL_TEMPLATE = 'customer\/password\/remind_email_template';\n\n    const XML_PATH_FORGOT_EMAIL_TEMPLATE = 'customer\/password\/forgot_email_template';\n\n    const XML_PATH_FORGOT_EMAIL_IDENTITY = 'customer\/password\/forgot_email_identity';\n\n    const XML_PATH_RESET_PASSWORD_TEMPLATE = 'customer\/password\/reset_password_template';\n\n    \/**\n     * @deprecated @see \\Magento\\Customer\\Model\\AccountConfirmation::XML_PATH_IS_CONFIRM\n     *\/\n    const XML_PATH_IS_CONFIRM = 'customer\/create_account\/confirm';\n\n    const XML_PATH_CONFIRM_EMAIL_TEMPLATE = 'customer\/create_account\/email_confirmation_template';\n\n    const XML_PATH_CONFIRMED_EMAIL_TEMPLATE = 'customer\/create_account\/email_confirmed_template';\n\n    const XML_PATH_GENERATE_HUMAN_FRIENDLY_ID = 'customer\/create_account\/generate_human_friendly_id';\n\n    const SUBSCRIBED_YES = 'yes';\n\n    const SUBSCRIBED_NO = 'no';\n\n    const ENTITY = 'customer';\n\n    const CUSTOMER_GRID_INDEXER_ID = 'customer_grid';\n\n    \/**\n     * Configuration path to expiration period of reset password link\n     *\/\n    const XML_PATH_CUSTOMER_RESET_PASSWORD_LINK_EXPIRATION_PERIOD = 'customer\/password\/reset_link_expiration_period';\n\n    \/**\n     * Model event prefix\n     *\n     * @var string\n     *\/\n    protected $_eventPrefix = 'customer';\n\n    \/**\n     * Name of the event object\n     *\n     * @var string\n     *\/\n    protected $_eventObject = 'customer';\n\n    \/**\n     * List of errors\n     *\n     * @var array\n     *\/\n    protected $_errors = [];\n\n    \/**\n     * Assoc array of customer attributes\n     *\n     * @var array\n     *\/\n    protected $_attributes;\n\n    \/**\n     * Customer addresses collection\n     *\n     * @var \\Magento\\Customer\\Model\\ResourceModel\\Address\\Collection\n     *\/\n    protected $_addressesCollection;\n\n    \/**\n     * Is model deletable\n     *\n     * @var boolean\n     *\/\n    protected $_isDeleteable = true;\n\n    \/**\n     * Is model readonly\n     *\n     * @var boolean\n     *\/\n    protected $_isReadonly = false;\n\n    \/**\n     * @var \\Magento\\Store\\Model\\StoreManagerInterface\n     *\/\n    protected $_storeManager;\n\n    \/**\n     * @var \\Magento\\Eav\\Model\\Config\n     *\/\n    protected $_config;\n\n    \/**\n     * @var \\Magento\\Framework\\App\\Config\\ScopeConfigInterface\n     *\/\n    protected $_scopeConfig;\n\n    \/**\n     * @var Share\n     *\/\n    protected $_configShare;\n\n    \/**\n     * @var AddressFactory\n     *\/\n    protected $_addressFactory;\n\n    \/**\n     * @var CollectionFactory\n     *\/\n    protected $_addressesFactory;\n\n    \/**\n     * @var \\Magento\\Framework\\Mail\\Template\\TransportBuilder\n     *\/\n    protected $_transportBuilder;\n\n    \/**\n     * @var GroupRepositoryInterface\n     *\/\n    protected $_groupRepository;\n\n    \/**\n     * @var \\Magento\\Framework\\Encryption\\EncryptorInterface\n     *\/\n    protected $_encryptor;\n\n    \/**\n     * @var Random\n     *\/\n    protected $mathRandom;\n\n    \/**\n     * @var \\Magento\\Framework\\Stdlib\\DateTime\n     *\/\n    protected $dateTime;\n\n    \/**\n     * @var CustomerInterfaceFactory\n     *\/\n    protected $customerDataFactory;\n\n    \/**\n     * @var DataObjectProcessor\n     *\/\n    protected $dataObjectProcessor;\n\n    \/**\n     * @var \\Magento\\Framework\\Api\\DataObjectHelper\n     *\/\n    protected $dataObjectHelper;\n\n    \/**\n     * @var \\Magento\\Customer\\Api\\CustomerMetadataInterface\n     *\/\n    protected $metadataService;\n\n    \/**\n     * @var \\Magento\\Framework\\Indexer\\IndexerRegistry\n     *\/\n    protected $indexerRegistry;\n\n    \/**\n     * @var AccountConfirmation\n     *\/\n    private $accountConfirmation;\n\n    \/**\n     * Caching property to store customer address data models by the address ID.\n     *\n     * @var array\n     *\/\n    private $storedAddress;\n\n    \/**\n     * @var IndexerInterface|null\n     *\/\n    private $indexer;\n\n    \/**\n     * @param \\Magento\\Framework\\Model\\Context $context\n     * @param \\Magento\\Framework\\Registry $registry\n     * @param \\Magento\\Store\\Model\\StoreManagerInterface $storeManager\n     * @param \\Magento\\Eav\\Model\\Config $config\n     * @param ScopeConfigInterface $scopeConfig\n     * @param ResourceCustomer $resource\n     * @param Share $configShare\n     * @param AddressFactory $addressFactory\n     * @param CollectionFactory $addressesFactory\n     * @param \\Magento\\Framework\\Mail\\Template\\TransportBuilder $transportBuilder\n     * @param GroupRepositoryInterface $groupRepository\n     * @param \\Magento\\Framework\\Encryption\\EncryptorInterface $encryptor\n     * @param \\Magento\\Framework\\Stdlib\\DateTime $dateTime\n     * @param CustomerInterfaceFactory $customerDataFactory\n     * @param DataObjectProcessor $dataObjectProcessor\n     * @param \\Magento\\Framework\\Api\\DataObjectHelper $dataObjectHelper\n     * @param CustomerMetadataInterface $metadataService\n     * @param \\Magento\\Framework\\Indexer\\IndexerRegistry $indexerRegistry\n     * @param \\Magento\\Framework\\Data\\Collection\\AbstractDb|null $resourceCollection\n     * @param array $data\n     * @param AccountConfirmation|null $accountConfirmation\n     * @param Random|null $mathRandom\n     *\n     * @SuppressWarnings(PHPMD.ExcessiveParameterList)\n     *\/\n    public function __construct(\n        \\Magento\\Framework\\Model\\Context $context,\n        \\Magento\\Framework\\Registry $registry,\n        \\Magento\\Store\\Model\\StoreManagerInterface $storeManager,\n        \\Magento\\Eav\\Model\\Config $config,\n        \\Magento\\Framework\\App\\Config\\ScopeConfigInterface $scopeConfig,\n        \\Magento\\Customer\\Model\\ResourceModel\\Customer $resource,\n        \\Magento\\Customer\\Model\\Config\\Share $configShare,\n        \\Magento\\Customer\\Model\\AddressFactory $addressFactory,\n        \\Magento\\Customer\\Model\\ResourceModel\\Address\\CollectionFactory $addressesFactory,\n        \\Magento\\Framework\\Mail\\Template\\TransportBuilder $transportBuilder,\n        GroupRepositoryInterface $groupRepository,\n        \\Magento\\Framework\\Encryption\\EncryptorInterface $encryptor,\n        \\Magento\\Framework\\Stdlib\\DateTime $dateTime,\n        CustomerInterfaceFactory $customerDataFactory,\n        DataObjectProcessor $dataObjectProcessor,\n        \\Magento\\Framework\\Api\\DataObjectHelper $dataObjectHelper,\n        \\Magento\\Customer\\Api\\CustomerMetadataInterface $metadataService,\n        \\Magento\\Framework\\Indexer\\IndexerRegistry $indexerRegistry,\n        \\Magento\\Framework\\Data\\Collection\\AbstractDb $resourceCollection = null,\n        array $data = [],\n        AccountConfirmation $accountConfirmation = null,\n        Random $mathRandom = null\n    ) {\n        $this->metadataService = $metadataService;\n        $this->_scopeConfig = $scopeConfig;\n        $this->_storeManager = $storeManager;\n        $this->_config = $config;\n        $this->_configShare = $configShare;\n        $this->_addressFactory = $addressFactory;\n        $this->_addressesFactory = $addressesFactory;\n        $this->_transportBuilder = $transportBuilder;\n        $this->_groupRepository = $groupRepository;\n        $this->_encryptor = $encryptor;\n        $this->dateTime = $dateTime;\n        $this->customerDataFactory = $customerDataFactory;\n        $this->dataObjectProcessor = $dataObjectProcessor;\n        $this->dataObjectHelper = $dataObjectHelper;\n        $this->indexerRegistry = $indexerRegistry;\n        $this->accountConfirmation = $accountConfirmation ?: ObjectManager::getInstance()\n            ->get(AccountConfirmation::class);\n        $this->mathRandom = $mathRandom ?: ObjectManager::getInstance()->get(Random::class);\n        parent::__construct(\n            $context,\n            $registry,\n            $resource,\n            $resourceCollection,\n            $data\n        );\n    }\n\n    \/**\n     * Micro-caching optimization\n     *\n     * @return IndexerInterface\n     *\/\n    private function getIndexer() : IndexerInterface\n    {\n        if ($this->indexer === null) {\n            $this->indexer = $this->indexerRegistry->get(self::CUSTOMER_GRID_INDEXER_ID);\n        }\n        return $this->indexer;\n    }\n\n    \/**\n     * Initialize customer model\n     *\n     * @return void\n     *\/\n    public function _construct()\n    {\n        $this->_init(\\Magento\\Customer\\Model\\ResourceModel\\Customer::class);\n    }\n\n    \/**\n     * Retrieve customer model with customer data\n     *\n     * @return \\Magento\\Customer\\Api\\Data\\CustomerInterface\n     *\/\n    public function getDataModel()\n    {\n        $customerData = $this->getData();\n        $addressesData = [];\n        \/** @var \\Magento\\Customer\\Model\\Address $address *\/\n        foreach ($this->getAddresses() as $address) {\n            if (!isset($this->storedAddress[$address->getId()])) {\n                $this->storedAddress[$address->getId()] = $address->getDataModel();\n            }\n            $addressesData[] = $this->storedAddress[$address->getId()];\n        }\n        $customerDataObject = $this->customerDataFactory->create();\n        $this->dataObjectHelper->populateWithArray(\n            $customerDataObject,\n            $customerData,\n            \\Magento\\Customer\\Api\\Data\\CustomerInterface::class\n        );\n        $customerDataObject->setAddresses($addressesData)\n            ->setId($this->getId());\n        return $customerDataObject;\n    }\n\n    \/**\n     * Update customer data\n     *\n     * @param \\Magento\\Customer\\Api\\Data\\CustomerInterface $customer\n     * @return $this\n     *\/\n    public function updateData($customer)\n    {\n        $customerDataAttributes = $this->dataObjectProcessor->buildOutputDataArray(\n            $customer,\n            \\Magento\\Customer\\Api\\Data\\CustomerInterface::class\n        );\n\n        foreach ($customerDataAttributes as $attributeCode => $attributeData) {\n            if ($attributeCode == 'password') {\n                continue;\n            }\n            $this->setDataUsingMethod($attributeCode, $attributeData);\n        }\n\n        $customAttributes = $customer->getCustomAttributes();\n        if ($customAttributes !== null) {\n            foreach ($customAttributes as $attribute) {\n                $this->setData($attribute->getAttributeCode(), $attribute->getValue());\n            }\n        }\n\n        $customerId = $customer->getId();\n        if ($customerId) {\n            $this->setId($customerId);\n        }\n\n        return $this;\n    }\n\n    \/**\n     * Retrieve customer sharing configuration model\n     *\n     * @return Share\n     *\/\n    public function getSharingConfig()\n    {\n        return $this->_configShare;\n    }\n\n    \/**\n     * Authenticate customer\n     *\n     * @param  string $login\n     * @param  string $password\n     * @return bool\n     * @throws \\Magento\\Framework\\Exception\\LocalizedException\n     * Use \\Magento\\Customer\\Api\\AccountManagementInterface::authenticate\n     *\/\n    public function authenticate($login, $password)\n    {\n        $this->loadByEmail($login);\n        if ($this->getConfirmation() &amp;&amp;\n            $this->accountConfirmation->isConfirmationRequired($this->getWebsiteId(), $this->getId(), $this->getEmail())\n        ) {\n            throw new EmailNotConfirmedException(\n                __(\"This account isn't confirmed. Verify and try again.\")\n            );\n        }\n        if (!$this->validatePassword($password)) {\n            throw new InvalidEmailOrPasswordException(\n                __('Invalid login or password.')\n            );\n        }\n        $this->_eventManager->dispatch(\n            'customer_customer_authenticated',\n            ['model' => $this, 'password' => $password]\n        );\n\n        return true;\n    }\n\n    \/**\n     * Load customer by email\n     *\n     * @param string $customerEmail\n     * @return $this\n     * @throws \\Magento\\Framework\\Exception\\LocalizedException\n     *\/\n    public function loadByEmail($customerEmail)\n    {\n        $this->_getResource()->loadByEmail($this, $customerEmail);\n        return $this;\n    }\n\n    \/**\n     * Change customer password\n     *\n     * @param string $newPassword\n     * @return $this\n     * @throws \\Magento\\Framework\\Exception\\LocalizedException\n     *\/\n    public function changePassword($newPassword)\n    {\n        $this->_getResource()->changePassword($this, $newPassword);\n        return $this;\n    }\n\n    \/**\n     * Get full customer name\n     *\n     * @return string\n     * @throws \\Magento\\Framework\\Exception\\LocalizedException\n     *\/\n    public function getName()\n    {\n        $name = '';\n\n        if ($this->_config->getAttribute('customer', 'prefix')->getIsVisible() &amp;&amp; $this->getPrefix()) {\n            $name .= $this->getPrefix() . ' ';\n        }\n        $name .= $this->getFirstname();\n        if ($this->_config->getAttribute('customer', 'middlename')->getIsVisible() &amp;&amp; $this->getMiddlename()) {\n            $name .= ' ' . $this->getMiddlename();\n        }\n        $name .= ' ' . $this->getLastname();\n        if ($this->_config->getAttribute('customer', 'suffix')->getIsVisible() &amp;&amp; $this->getSuffix()) {\n            $name .= ' ' . $this->getSuffix();\n        }\n        return $name;\n    }\n\n    \/**\n     * Add address to address collection\n     *\n     * @param Address $address\n     * @return $this\n     * @throws \\Magento\\Framework\\Exception\\LocalizedException\n     *\/\n    public function addAddress(Address $address)\n    {\n        $this->getAddressesCollection()->addItem($address);\n        return $this;\n    }\n\n    \/**\n     * Retrieve customer address by address id\n     *\n     * @param   int $addressId\n     * @return  Address\n     *\/\n    public function getAddressById($addressId)\n    {\n        return $this->_createAddressInstance()->load($addressId);\n    }\n\n    \/**\n     * Getting customer address object from collection by identifier\n     *\n     * @param int $addressId\n     * @return Address\n     * @throws \\Magento\\Framework\\Exception\\LocalizedException\n     *\/\n    public function getAddressItemById($addressId)\n    {\n        return $this->getAddressesCollection()->getItemById($addressId);\n    }\n\n    \/**\n     * Retrieve not loaded address collection\n     *\n     * @return \\Magento\\Customer\\Model\\ResourceModel\\Address\\Collection\n     *\/\n    public function getAddressCollection()\n    {\n        return $this->_createAddressCollection();\n    }\n\n    \/**\n     * Customer addresses collection\n     *\n     * @return \\Magento\\Customer\\Model\\ResourceModel\\Address\\Collection\n     * @throws \\Magento\\Framework\\Exception\\LocalizedException\n     *\/\n    public function getAddressesCollection()\n    {\n        if ($this->_addressesCollection === null) {\n            $this->_addressesCollection = $this->getAddressCollection()->setCustomerFilter(\n                $this\n            )->addAttributeToSelect(\n                '*'\n            );\n            foreach ($this->_addressesCollection as $address) {\n                $address->setCustomer($this);\n            }\n        }\n\n        return $this->_addressesCollection;\n    }\n\n    \/**\n     * Retrieve customer address array\n     *\n     * @return \\Magento\\Framework\\DataObject[]\n     *\/\n    public function getAddresses()\n    {\n        return $this->getAddressesCollection()->getItems();\n    }\n\n    \/**\n     * Retrieve all customer attributes\n     *\n     * @return Attribute[]\n     * @throws \\Magento\\Framework\\Exception\\LocalizedException\n     *\/\n    public function getAttributes()\n    {\n        if ($this->_attributes === null) {\n            $this->_attributes = $this->_getResource()->loadAllAttributes($this)->getSortedAttributes();\n        }\n        return $this->_attributes;\n    }\n\n    \/**\n     * Get customer attribute model object\n     *\n     * @param   string $attributeCode\n     * @return  \\Magento\\Customer\\Model\\ResourceModel\\Attribute | null\n     *\/\n    public function getAttribute($attributeCode)\n    {\n        $this->getAttributes();\n        if (isset($this->_attributes[$attributeCode])) {\n            return $this->_attributes[$attributeCode];\n        }\n        return null;\n    }\n\n    \/**\n     * Set plain and hashed password\n     *\n     * @param string $password\n     * @return $this\n     *\/\n    public function setPassword($password)\n    {\n        $this->setData('password', $password);\n        $this->setPasswordHash($this->hashPassword($password));\n        return $this;\n    }\n\n    \/**\n     * Hash customer password\n     *\n     * @param string $password\n     * @param bool|int|string $salt\n     * @return string\n     *\/\n    public function hashPassword($password, $salt = true)\n    {\n        return $this->_encryptor->getHash($password, $salt);\n    }\n\n    \/**\n     * Validate password with salted hash\n     *\n     * @param string $password\n     * @return boolean\n     * @throws \\Exception\n     *\/\n    public function validatePassword($password)\n    {\n        $hash = $this->getPasswordHash();\n        if (!$hash) {\n            return false;\n        }\n        return $this->_encryptor->validateHash($password, $hash);\n    }\n\n    \/**\n     * Encrypt password\n     *\n     * @param   string $password\n     * @return  string\n     *\/\n    public function encryptPassword($password)\n    {\n        return $this->_encryptor->encrypt($password);\n    }\n\n    \/**\n     * Decrypt password\n     *\n     * @param   string $password\n     * @return  string\n     *\/\n    public function decryptPassword($password)\n    {\n        return $this->_encryptor->decrypt($password);\n    }\n\n    \/**\n     * Retrieve default address by type(attribute)\n     *\n     * @param   string $attributeCode address type attribute code\n     * @return  Address|false\n     *\/\n    public function getPrimaryAddress($attributeCode)\n    {\n        $primaryAddress = $this->getAddressesCollection()->getItemById($this->getData($attributeCode));\n\n        return $primaryAddress ? $primaryAddress : false;\n    }\n\n    \/**\n     * Get customer default billing address\n     *\n     * @return Address\n     *\/\n    public function getPrimaryBillingAddress()\n    {\n        return $this->getPrimaryAddress('default_billing');\n    }\n\n    \/**\n     * Get customer default billing address\n     *\n     * @return Address\n     *\/\n    public function getDefaultBillingAddress()\n    {\n        return $this->getPrimaryBillingAddress();\n    }\n\n    \/**\n     * Get default customer shipping address\n     *\n     * @return Address\n     *\/\n    public function getPrimaryShippingAddress()\n    {\n        return $this->getPrimaryAddress('default_shipping');\n    }\n\n    \/**\n     * Get default customer shipping address\n     *\n     * @return Address\n     *\/\n    public function getDefaultShippingAddress()\n    {\n        return $this->getPrimaryShippingAddress();\n    }\n\n    \/**\n     * Retrieve ids of default addresses\n     *\n     * @return array\n     *\/\n    public function getPrimaryAddressIds()\n    {\n        $ids = [];\n        if ($this->getDefaultBilling()) {\n            $ids[] = $this->getDefaultBilling();\n        }\n        if ($this->getDefaultShipping()) {\n            $ids[] = $this->getDefaultShipping();\n        }\n        return $ids;\n    }\n\n    \/**\n     * Retrieve all customer default addresses\n     *\n     * @return Address[]\n     *\/\n    public function getPrimaryAddresses()\n    {\n        $addresses = [];\n        $primaryBilling = $this->getPrimaryBillingAddress();\n        if ($primaryBilling) {\n            $addresses[] = $primaryBilling;\n            $primaryBilling->setIsPrimaryBilling(true);\n        }\n\n        $primaryShipping = $this->getPrimaryShippingAddress();\n        if ($primaryShipping) {\n            if ($primaryBilling &amp;&amp; $primaryBilling->getId() == $primaryShipping->getId()) {\n                $primaryBilling->setIsPrimaryShipping(true);\n            } else {\n                $primaryShipping->setIsPrimaryShipping(true);\n                $addresses[] = $primaryShipping;\n            }\n        }\n        return $addresses;\n    }\n\n    \/**\n     * Retrieve not default addresses\n     *\n     * @return Address[]\n     *\/\n    public function getAdditionalAddresses()\n    {\n        $addresses = [];\n        $primatyIds = $this->getPrimaryAddressIds();\n        foreach ($this->getAddressesCollection() as $address) {\n            if (!in_array($address->getId(), $primatyIds)) {\n                $addresses[] = $address;\n            }\n        }\n        return $addresses;\n    }\n\n    \/**\n     * Check if address is primary\n     *\n     * @param Address $address\n     * @return boolean\n     *\/\n    public function isAddressPrimary(Address $address)\n    {\n        if (!$address->getId()) {\n            return false;\n        }\n        return $address->getId() == $this->getDefaultBilling() || $address->getId() == $this->getDefaultShipping();\n    }\n\n    \/**\n     * Send email with new account related information\n     *\n     * @param string $type\n     * @param string $backUrl\n     * @param string $storeId\n     * @return $this\n     * @throws \\Magento\\Framework\\Exception\\LocalizedException\n     *\/\n    public function sendNewAccountEmail($type = 'registered', $backUrl = '', $storeId = '0')\n    {\n        $types = $this->getTemplateTypes();\n\n        if (!isset($types[$type])) {\n            throw new \\Magento\\Framework\\Exception\\LocalizedException(\n                __('The transactional account email type is incorrect. Verify and try again.')\n            );\n        }\n\n        if (!$storeId) {\n            $storeId = $this->_getWebsiteStoreId($this->getSendemailStoreId());\n        }\n\n        $this->_sendEmailTemplate(\n            $types[$type],\n            self::XML_PATH_REGISTER_EMAIL_IDENTITY,\n            ['customer' => $this, 'back_url' => $backUrl, 'store' => $this->getStore()],\n            $storeId\n        );\n\n        return $this;\n    }\n\n    \/**\n     * Check if accounts confirmation is required in config\n     *\n     * @return bool\n     * @deprecated 101.0.4\n     * @see AccountConfirmation::isConfirmationRequired\n     *\/\n    public function isConfirmationRequired()\n    {\n        $websiteId = $this->getWebsiteId() ? $this->getWebsiteId() : null;\n\n        return $this->accountConfirmation->isConfirmationRequired($websiteId, $this->getId(), $this->getEmail());\n    }\n\n    \/**\n     * Generate random confirmation key\n     *\n     * @return string\n     *\/\n    public function getRandomConfirmationKey()\n    {\n        return $this->mathRandom->getRandomString(32);\n    }\n\n    \/**\n     * Send email with new customer password\n     *\n     * @return $this\n     *\/\n    public function sendPasswordReminderEmail()\n    {\n        $this->_sendEmailTemplate(\n            self::XML_PATH_REMIND_EMAIL_TEMPLATE,\n            self::XML_PATH_FORGOT_EMAIL_IDENTITY,\n            ['customer' => $this, 'store' => $this->getStore()],\n            $this->getStoreId()\n        );\n\n        return $this;\n    }\n\n    \/**\n     * Send corresponding email template\n     *\n     * @param string $template configuration path of email template\n     * @param string $sender configuration path of email identity\n     * @param array $templateParams\n     * @param int|null $storeId\n     * @return $this\n     *\/\n    protected function _sendEmailTemplate($template, $sender, $templateParams = [], $storeId = null)\n    {\n        \/** @var \\Magento\\Framework\\Mail\\TransportInterface $transport *\/\n        $transport = $this->_transportBuilder->setTemplateIdentifier(\n            $this->_scopeConfig->getValue($template, ScopeInterface::SCOPE_STORE, $storeId)\n        )->setTemplateOptions(\n            ['area' => \\Magento\\Framework\\App\\Area::AREA_FRONTEND, 'store' => $storeId]\n        )->setTemplateVars(\n            $templateParams\n        )->setFrom(\n            $this->_scopeConfig->getValue($sender, ScopeInterface::SCOPE_STORE, $storeId)\n        )->addTo(\n            $this->getEmail(),\n            $this->getName()\n        )->getTransport();\n        $transport->sendMessage();\n\n        return $this;\n    }\n\n    \/**\n     * Send email with reset password confirmation link\n     *\n     * @return $this\n     *\/\n    public function sendPasswordResetConfirmationEmail()\n    {\n        $storeId = $this->getStoreId();\n        if (!$storeId) {\n            $storeId = $this->_getWebsiteStoreId();\n        }\n\n        $this->_sendEmailTemplate(\n            self::XML_PATH_FORGOT_EMAIL_TEMPLATE,\n            self::XML_PATH_FORGOT_EMAIL_IDENTITY,\n            ['customer' => $this, 'store' => $this->getStore()],\n            $storeId\n        );\n\n        return $this;\n    }\n\n    \/**\n     * Retrieve customer group identifier\n     *\n     * @return int\n     *\/\n    public function getGroupId()\n    {\n        if (!$this->hasData('group_id')) {\n            $storeId = $this->getStoreId() ? $this->getStoreId() : $this->_storeManager->getStore()->getId();\n            $groupId = $this->_scopeConfig->getValue(\n                GroupManagement::XML_PATH_DEFAULT_ID,\n                ScopeInterface::SCOPE_STORE,\n                $storeId\n            );\n            $this->setData('group_id', $groupId);\n        }\n        return $this->getData('group_id');\n    }\n\n    \/**\n     * Retrieve customer tax class identifier\n     *\n     * @return int\n     *\/\n    public function getTaxClassId()\n    {\n        if (!$this->getData('tax_class_id')) {\n            $groupTaxClassId = $this->_groupRepository->getById($this->getGroupId())->getTaxClassId();\n            $this->setData('tax_class_id', $groupTaxClassId);\n        }\n        return $this->getData('tax_class_id');\n    }\n\n    \/**\n     * Retrieve store where customer was created\n     *\n     * @return \\Magento\\Store\\Model\\Store\n     *\/\n    public function getStore()\n    {\n        return $this->_storeManager->getStore($this->getStoreId());\n    }\n\n    \/**\n     * Retrieve shared store ids\n     *\n     * @return array\n     *\/\n    public function getSharedStoreIds()\n    {\n        $ids = $this->_getData('shared_store_ids');\n        if ($ids === null) {\n            $ids = [];\n            if ((bool)$this->getSharingConfig()->isWebsiteScope()) {\n                $ids = $this->_storeManager->getWebsite($this->getWebsiteId())->getStoreIds();\n            } else {\n                foreach ($this->_storeManager->getStores() as $store) {\n                    $ids[] = $store->getId();\n                }\n            }\n            $this->setData('shared_store_ids', $ids);\n        }\n\n        return $ids;\n    }\n\n    \/**\n     * Retrieve shared website ids\n     *\n     * @return int[]\n     *\/\n    public function getSharedWebsiteIds()\n    {\n        $ids = $this->_getData('shared_website_ids');\n        if ($ids === null) {\n            $ids = [];\n            if ((bool)$this->getSharingConfig()->isWebsiteScope()) {\n                $ids[] = $this->getWebsiteId();\n            } else {\n                foreach ($this->_storeManager->getWebsites() as $website) {\n                    $ids[] = $website->getId();\n                }\n            }\n            $this->setData('shared_website_ids', $ids);\n        }\n        return $ids;\n    }\n\n    \/**\n     * Retrieve attribute set id for customer.\n     *\n     * @return int\n     * @since 102.0.1\n     *\/\n    public function getAttributeSetId()\n    {\n        \/\/ phpstan:ignore \"Call to an undefined static method*\"\n        return parent::getAttributeSetId() ?: CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER;\n    }\n\n    \/**\n     * Set store to customer\n     *\n     * @param \\Magento\\Store\\Model\\Store $store\n     * @return $this\n     *\/\n    public function setStore(\\Magento\\Store\\Model\\Store $store)\n    {\n        $this->setStoreId($store->getId());\n        $this->setWebsiteId($store->getWebsite()->getId());\n        return $this;\n    }\n\n    \/**\n     * Validate customer attribute values.\n     *\n     * @deprecated 100.1.0\n     * @return bool\n     *\/\n    public function validate()\n    {\n        return true;\n    }\n\n    \/**\n     * Unset subscription\n     *\n     * @return $this\n     *\/\n    public function unsetSubscription()\n    {\n        if (isset($this->_isSubscribed)) {\n            unset($this->_isSubscribed);\n        }\n        return $this;\n    }\n\n    \/**\n     * Clean all addresses\n     *\n     * @return void\n     *\/\n    public function cleanAllAddresses()\n    {\n        $this->_addressesCollection = null;\n    }\n\n    \/**\n     * Add error\n     *\n     * @param mixed $error\n     * @return $this\n     *\/\n    public function addError($error)\n    {\n        $this->_errors[] = $error;\n        return $this;\n    }\n\n    \/**\n     * Retrieve errors\n     *\n     * @return array\n     *\/\n    public function getErrors()\n    {\n        return $this->_errors;\n    }\n\n    \/**\n     * Reset errors array\n     *\n     * @return $this\n     *\/\n    public function resetErrors()\n    {\n        $this->_errors = [];\n        return $this;\n    }\n\n    \/**\n     * Processing object after save data\n     *\n     * @return $this\n     *\/\n    public function afterSave()\n    {\n        if ($this->getIndexer()->getState()->getStatus() == StateInterface::STATUS_VALID) {\n            $this->_getResource()->addCommitCallback([$this, 'reindex']);\n        }\n        return parent::afterSave();\n    }\n\n    \/**\n     * Init indexing process after customer delete\n     *\n     * @return \\Magento\\Framework\\Model\\AbstractModel\n     *\/\n    public function afterDeleteCommit()\n    {\n        $this->reindex();\n        return parent::afterDeleteCommit();\n    }\n\n    \/**\n     * Init indexing process after customer save\n     *\n     * @return void\n     *\/\n    public function reindex()\n    {\n        $this->getIndexer()->reindexRow($this->getId());\n    }\n\n    \/**\n     * Get customer created at date timestamp\n     *\n     * @return int|null\n     *\/\n    public function getCreatedAtTimestamp()\n    {\n        $date = $this->getCreatedAt();\n        if ($date) {\n            return (new \\DateTime($date))->getTimestamp();\n        }\n        return null;\n    }\n\n    \/**\n     * Reset all model data\n     *\n     * @return $this\n     *\/\n    public function reset()\n    {\n        $this->setData([]);\n        $this->setOrigData();\n        $this->_attributes = null;\n\n        return $this;\n    }\n\n    \/**\n     * Checks model is deletable\n     *\n     * @return boolean\n     *\/\n    public function isDeleteable()\n    {\n        return $this->_isDeleteable;\n    }\n\n    \/**\n     * Set is deletable flag\n     *\n     * @param boolean $value\n     * @return $this\n     *\/\n    public function setIsDeleteable($value)\n    {\n        $this->_isDeleteable = (bool)$value;\n        return $this;\n    }\n\n    \/**\n     * Checks model is readonly\n     *\n     * @return boolean\n     *\/\n    public function isReadonly()\n    {\n        return $this->_isReadonly;\n    }\n\n    \/**\n     * Set is readonly flag\n     *\n     * @param boolean $value\n     * @return $this\n     *\/\n    public function setIsReadonly($value)\n    {\n        $this->_isReadonly = (bool)$value;\n        return $this;\n    }\n\n    \/**\n     * Check whether confirmation may be skipped when registering using certain email address\n     *\n     * @return bool\n     * @deprecated 101.0.4\n     * @see AccountConfirmation::isConfirmationRequired\n     *\/\n    protected function canSkipConfirmation()\n    {\n        if (!$this->getId()) {\n            return false;\n        }\n\n        \/* If an email was used to start the registration process and it is the same email as the one\n           used to register, then this can skip confirmation.\n           *\/\n        $skipConfirmationIfEmail = $this->_registry->registry(\"skip_confirmation_if_email\");\n        if (!$skipConfirmationIfEmail) {\n            return false;\n        }\n\n        return strtolower($skipConfirmationIfEmail) === strtolower($this->getEmail());\n    }\n\n    \/**\n     * Clone current object\n     *\n     * @return void\n     *\/\n    public function __clone()\n    {\n        $newAddressCollection = $this->getPrimaryAddresses();\n        $newAddressCollection = array_merge($newAddressCollection, $this->getAdditionalAddresses());\n        $this->setId(null);\n        $this->cleanAllAddresses();\n        foreach ($newAddressCollection as $address) {\n            $this->addAddress(clone $address);\n        }\n    }\n\n    \/**\n     * Return Entity Type instance\n     *\n     * @return \\Magento\\Eav\\Model\\Entity\\Type\n     *\/\n    public function getEntityType()\n    {\n        return $this->_getResource()->getEntityType();\n    }\n\n    \/**\n     * Get either first store ID from a set website or the provided as default\n     *\n     * @param int|string|null $defaultStoreId\n     *\n     * @return int\n     *\/\n    protected function _getWebsiteStoreId($defaultStoreId = null)\n    {\n        if ($this->getWebsiteId() != 0 &amp;&amp; empty($defaultStoreId)) {\n            $storeIds = $this->_storeManager->getWebsite($this->getWebsiteId())->getStoreIds();\n            reset($storeIds);\n            $defaultStoreId = current($storeIds);\n        }\n        return $defaultStoreId;\n    }\n\n    \/**\n     * Change reset password link token\n     *\n     * Stores new reset password link token\n     *\n     * @param string $passwordLinkToken\n     * @return $this\n     * @throws \\Magento\\Framework\\Exception\\AuthenticationException\n     *\/\n    public function changeResetPasswordLinkToken($passwordLinkToken)\n    {\n        if (!is_string($passwordLinkToken) || empty($passwordLinkToken)) {\n            throw new AuthenticationException(\n                __('A valid password reset token is missing. Enter and try again.')\n            );\n        }\n        $this->_getResource()->changeResetPasswordLinkToken($this, $passwordLinkToken);\n        return $this;\n    }\n\n    \/**\n     * Check if current reset password link token is expired\n     *\n     * @return boolean\n     *\/\n    public function isResetPasswordLinkTokenExpired()\n    {\n        $linkToken = $this->getRpToken();\n        $linkTokenCreatedAt = $this->getRpTokenCreatedAt();\n\n        if (empty($linkToken) || empty($linkTokenCreatedAt)) {\n            return true;\n        }\n\n        $expirationPeriod = $this->getResetPasswordLinkExpirationPeriod();\n\n        $currentTimestamp = (new \\DateTime())->getTimestamp();\n        $tokenTimestamp = (new \\DateTime($linkTokenCreatedAt))->getTimestamp();\n        if ($tokenTimestamp > $currentTimestamp) {\n            return true;\n        }\n\n        $dayDifference = floor(($currentTimestamp - $tokenTimestamp) \/ (24 * 60 * 60));\n        if ($dayDifference >= $expirationPeriod) {\n            return true;\n        }\n\n        return false;\n    }\n\n    \/**\n     * Retrieve customer reset password link expiration period in days\n     *\n     * @return int\n     *\/\n    public function getResetPasswordLinkExpirationPeriod()\n    {\n        return (int)$this->_scopeConfig->getValue(\n            self::XML_PATH_CUSTOMER_RESET_PASSWORD_LINK_EXPIRATION_PERIOD,\n            ScopeConfigInterface::SCOPE_TYPE_DEFAULT\n        );\n    }\n\n    \/**\n     * Create Address from Factory\n     *\n     * @return Address\n     *\/\n    protected function _createAddressInstance()\n    {\n        return $this->_addressFactory->create();\n    }\n\n    \/**\n     * Create Address Collection from Factory\n     *\n     * @return \\Magento\\Customer\\Model\\ResourceModel\\Address\\Collection\n     *\/\n    protected function _createAddressCollection()\n    {\n        return $this->_addressesFactory->create();\n    }\n\n    \/**\n     * Get Template Types\n     *\n     * @return array\n     *\/\n    protected function getTemplateTypes()\n    {\n        \/**\n         * 'registered'   welcome email, when confirmation is disabled\n         * 'confirmed'    welcome email, when confirmation is enabled\n         * 'confirmation' email with confirmation link\n         *\/\n        $types = [\n            'registered' => self::XML_PATH_REGISTER_EMAIL_TEMPLATE,\n            'confirmed' => self::XML_PATH_CONFIRMED_EMAIL_TEMPLATE,\n            'confirmation' => self::XML_PATH_CONFIRM_EMAIL_TEMPLATE,\n        ];\n        return $types;\n    }\n\n    \/**\n     * Check if customer is locked\n     *\n     * @return boolean\n     * @since 100.1.0\n     *\/\n    public function isCustomerLocked()\n    {\n        if ($this->getLockExpires()) {\n            $lockExpires = new \\DateTime($this->getLockExpires());\n            if ($lockExpires > new \\DateTime()) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    \/**\n     * Return Password Confirmation\n     *\n     * @return string\n     * @since 100.1.0\n     *\/\n    public function getPasswordConfirm()\n    {\n        return (string) $this->getData('password_confirm');\n    }\n\n    \/**\n     * Return Password\n     *\n     * @return string\n     * @since 100.1.0\n     *\/\n    public function getPassword()\n    {\n        return (string) $this->getData('password');\n    }\n}<\/pre>\n\n\n\n<p>As you can see in the above class, it has implemented the CustomerInterface and defined all the abstract methods.<\/p>\n\n\n\n<p>That&#8217;s all for this article. There is a lot more to explain about this topic, but this will be too much for one article.<\/p>\n\n\n\n<p>I will explain repositories and management interfaces in my next article.<br>If you have any questions about this article, you can ask in the comments.<br>Thanks :).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction to service contract: In general, understanding a service contract is an agreement between the two parties, where one is the service provider, and the other is the service consumer. A service contract defines all the services that are going to be provided with some pre- and post-conditions. And it works in the same way <a href=\"https:\/\/webkul.com\/blog\/magento2-service-contract\/\">[&#8230;]<\/a><\/p>\n","protected":false},"author":33,"featured_media":70261,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[302],"tags":[],"class_list":["post-71572","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-magento2"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Magento 2 Service Contract - Webkul Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/webkul.com\/blog\/magento2-service-contract\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Magento 2 Service Contract - Webkul Blog\" \/>\n<meta property=\"og:description\" content=\"Introduction to service contract: In general, understanding a service contract is an agreement between the two parties, where one is the service provider, and the other is the service consumer. A service contract defines all the services that are going to be provided with some pre- and post-conditions. And it works in the same way [...]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/webkul.com\/blog\/magento2-service-contract\/\" \/>\n<meta property=\"og:site_name\" content=\"Webkul Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webkul\/\" \/>\n<meta property=\"article:published_time\" content=\"2017-01-14T08:50:56+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-12-23T06:53:54+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png\" \/>\n\t<meta property=\"og:image:width\" content=\"825\" \/>\n\t<meta property=\"og:image:height\" content=\"260\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Ashutosh Srivastava\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@webkul\" \/>\n<meta name=\"twitter:site\" content=\"@webkul\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ashutosh Srivastava\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/\"},\"author\":{\"name\":\"Ashutosh Srivastava\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/person\/5555025750ec4e4df34fadc78b083970\"},\"headline\":\"Magento 2 Service Contract\",\"datePublished\":\"2017-01-14T08:50:56+00:00\",\"dateModified\":\"2025-12-23T06:53:54+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/\"},\"wordCount\":565,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/webkul.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png\",\"articleSection\":[\"Magento2\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/webkul.com\/blog\/magento2-service-contract\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/\",\"url\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/\",\"name\":\"Magento 2 Service Contract - Webkul Blog\",\"isPartOf\":{\"@id\":\"https:\/\/webkul.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png\",\"datePublished\":\"2017-01-14T08:50:56+00:00\",\"dateModified\":\"2025-12-23T06:53:54+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/webkul.com\/blog\/magento2-service-contract\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/#primaryimage\",\"url\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png\",\"contentUrl\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png\",\"width\":825,\"height\":260},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/webkul.com\/blog\/magento2-service-contract\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/webkul.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Magento 2 Service Contract\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/webkul.com\/blog\/#website\",\"url\":\"https:\/\/webkul.com\/blog\/\",\"name\":\"Webkul Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/webkul.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/webkul.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/webkul.com\/blog\/#organization\",\"name\":\"WebKul Software Private Limited\",\"url\":\"https:\/\/webkul.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png\",\"contentUrl\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png\",\"width\":380,\"height\":380,\"caption\":\"WebKul Software Private Limited\"},\"image\":{\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webkul\/\",\"https:\/\/x.com\/webkul\",\"https:\/\/www.instagram.com\/webkul\/\",\"https:\/\/www.linkedin.com\/company\/webkul\",\"https:\/\/www.youtube.com\/user\/webkul\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/person\/5555025750ec4e4df34fadc78b083970\",\"name\":\"Ashutosh Srivastava\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/2f5312e6903909ffeb33aa5eb38e1c0bed8f498f92144f5f84065adf7e8708a6?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/2f5312e6903909ffeb33aa5eb38e1c0bed8f498f92144f5f84065adf7e8708a6?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g\",\"caption\":\"Ashutosh Srivastava\"},\"sameAs\":[\"http:\/\/webkul.com\"],\"url\":\"https:\/\/webkul.com\/blog\/author\/ashutosh\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Magento 2 Service Contract - Webkul Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/webkul.com\/blog\/magento2-service-contract\/","og_locale":"en_US","og_type":"article","og_title":"Magento 2 Service Contract - Webkul Blog","og_description":"Introduction to service contract: In general, understanding a service contract is an agreement between the two parties, where one is the service provider, and the other is the service consumer. A service contract defines all the services that are going to be provided with some pre- and post-conditions. And it works in the same way [...]","og_url":"https:\/\/webkul.com\/blog\/magento2-service-contract\/","og_site_name":"Webkul Blog","article_publisher":"https:\/\/www.facebook.com\/webkul\/","article_published_time":"2017-01-14T08:50:56+00:00","article_modified_time":"2025-12-23T06:53:54+00:00","og_image":[{"width":825,"height":260,"url":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png","type":"image\/png"}],"author":"Ashutosh Srivastava","twitter_card":"summary_large_image","twitter_creator":"@webkul","twitter_site":"@webkul","twitter_misc":{"Written by":"Ashutosh Srivastava","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/#article","isPartOf":{"@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/"},"author":{"name":"Ashutosh Srivastava","@id":"https:\/\/webkul.com\/blog\/#\/schema\/person\/5555025750ec4e4df34fadc78b083970"},"headline":"Magento 2 Service Contract","datePublished":"2017-01-14T08:50:56+00:00","dateModified":"2025-12-23T06:53:54+00:00","mainEntityOfPage":{"@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/"},"wordCount":565,"commentCount":2,"publisher":{"@id":"https:\/\/webkul.com\/blog\/#organization"},"image":{"@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/#primaryimage"},"thumbnailUrl":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png","articleSection":["Magento2"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/webkul.com\/blog\/magento2-service-contract\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/","url":"https:\/\/webkul.com\/blog\/magento2-service-contract\/","name":"Magento 2 Service Contract - Webkul Blog","isPartOf":{"@id":"https:\/\/webkul.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/#primaryimage"},"image":{"@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/#primaryimage"},"thumbnailUrl":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png","datePublished":"2017-01-14T08:50:56+00:00","dateModified":"2025-12-23T06:53:54+00:00","breadcrumb":{"@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/webkul.com\/blog\/magento2-service-contract\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/#primaryimage","url":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png","contentUrl":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2017\/01\/Magneto-Code-Snippet.png","width":825,"height":260},{"@type":"BreadcrumbList","@id":"https:\/\/webkul.com\/blog\/magento2-service-contract\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/webkul.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Magento 2 Service Contract"}]},{"@type":"WebSite","@id":"https:\/\/webkul.com\/blog\/#website","url":"https:\/\/webkul.com\/blog\/","name":"Webkul Blog","description":"","publisher":{"@id":"https:\/\/webkul.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/webkul.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/webkul.com\/blog\/#organization","name":"WebKul Software Private Limited","url":"https:\/\/webkul.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png","contentUrl":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png","width":380,"height":380,"caption":"WebKul Software Private Limited"},"image":{"@id":"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webkul\/","https:\/\/x.com\/webkul","https:\/\/www.instagram.com\/webkul\/","https:\/\/www.linkedin.com\/company\/webkul","https:\/\/www.youtube.com\/user\/webkul\/"]},{"@type":"Person","@id":"https:\/\/webkul.com\/blog\/#\/schema\/person\/5555025750ec4e4df34fadc78b083970","name":"Ashutosh Srivastava","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/webkul.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/2f5312e6903909ffeb33aa5eb38e1c0bed8f498f92144f5f84065adf7e8708a6?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2f5312e6903909ffeb33aa5eb38e1c0bed8f498f92144f5f84065adf7e8708a6?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g","caption":"Ashutosh Srivastava"},"sameAs":["http:\/\/webkul.com"],"url":"https:\/\/webkul.com\/blog\/author\/ashutosh\/"}]}},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts\/71572","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/comments?post=71572"}],"version-history":[{"count":21,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts\/71572\/revisions"}],"predecessor-version":[{"id":518474,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts\/71572\/revisions\/518474"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/media\/70261"}],"wp:attachment":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/media?parent=71572"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/categories?post=71572"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/tags?post=71572"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}