classes/XLite/Model/Profile.php line 66

Open in your IDE?
  1. <?php
  2. /**
  3.  * Copyright (c) 2001-present X-Cart Holdings LLC. All rights reserved.
  4.  * See https://www.x-cart.com/license-agreement.html for license details.
  5.  */
  6. namespace XLite\Model;
  7. use ApiPlatform\Core\Annotation as ApiPlatform;
  8. use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
  9. use Doctrine\ORM\Mapping as ORM;
  10. use XCart\Framework\ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\IntegerDateFilter;
  11. use XLite\API\Endpoint\Profile\DTO\ProfileInput as Input;
  12. use XLite\API\Endpoint\Profile\DTO\ProfileOutput as Output;
  13. use XLite\Core\Translation;
  14. /**
  15.  * The "profile" model class
  16.  *
  17.  * @ORM\Entity
  18.  * @ORM\Table  (name="profiles",
  19.  *      indexes={
  20.  *          @ORM\Index (name="login", columns={"login"}),
  21.  *          @ORM\Index (name="order_id", columns={"order_id"}),
  22.  *          @ORM\Index (name="password", columns={"password"}),
  23.  *          @ORM\Index (name="access_level", columns={"access_level"}),
  24.  *          @ORM\Index (name="first_login", columns={"first_login"}),
  25.  *          @ORM\Index (name="last_login", columns={"last_login"}),
  26.  *          @ORM\Index (name="status", columns={"status"})
  27.  *      }
  28.  * )
  29.  * @ApiPlatform\ApiResource(
  30.  *     input=Input::class,
  31.  *     output=Output::class,
  32.  *     itemOperations={
  33.  *          "get"={
  34.  *              "method"="GET",
  35.  *              "path"="/profiles/{profile_id}.{_format}",
  36.  *              "identifiers"={"profile_id"},
  37.  *              "requirements"={"profile_id"="\d+"}
  38.  *          },
  39.  *          "put"={
  40.  *              "method"="PUT",
  41.  *              "path"="/profiles/{profile_id}.{_format}",
  42.  *              "identifiers"={"profile_id"},
  43.  *              "requirements"={"profile_id"="\d+"}
  44.  *          },
  45.  *          "delete"={
  46.  *              "method"="DELETE",
  47.  *              "path"="/profiles/{profile_id}.{_format}",
  48.  *              "identifiers"={"profile_id"},
  49.  *              "requirements"={"profile_id"="\d+"}
  50.  *          }
  51.  *     },
  52.  *     collectionOperations={
  53.  *          "get"={
  54.  *              "method"="GET",
  55.  *              "path"="/profiles.{_format}",
  56.  *              "identifiers"={"profile_id"}
  57.  *          },
  58.  *          "post"={
  59.  *              "method"="POST",
  60.  *              "path"="/profiles.{_format}",
  61.  *              "identifiers"={"profile_id"},
  62.  *              "controller"="xcart.api.profile.controller"
  63.  *          }
  64.  *     }
  65.  * )
  66.  * @ApiPlatform\ApiFilter(IntegerDateFilter::class, properties={"first_login", "added"})
  67.  * @ApiPlatform\ApiFilter(SearchFilter::class, properties={"login"="partial", "searchFakeField"="partial"})
  68.  */
  69. class Profile extends AEntity
  70. {
  71.     /**
  72.      * Status codes
  73.      */
  74.     public const STATUS_ENABLED  'E';
  75.     public const STATUS_DISABLED 'D';
  76.     /**
  77.      * Merge flags
  78.      */
  79.     public const MERGE_ALL       3;
  80.     public const MERGE_ADDRESSES 1;
  81.     public const MERGE_ORDERS    2;
  82.     public const MIN_PASSWORD_LENGTH 8;
  83.     public const MAX_PASSWORD_LENGTH 64;
  84.     /**
  85.      * Profile unique ID
  86.      *
  87.      * @var integer
  88.      *
  89.      * @ORM\Id
  90.      * @ORM\GeneratedValue (strategy="AUTO")
  91.      * @ORM\Column         (type="integer")
  92.      */
  93.     protected $profile_id;
  94.     /**
  95.      * Old Login (e-mail)
  96.      *
  97.      * @var string
  98.      */
  99.     protected $oldLogin '';
  100.     /**
  101.      * Login (e-mail)
  102.      *
  103.      * @var string
  104.      *
  105.      * @ORM\Column (type="string", length=128)
  106.      */
  107.     protected $login '';
  108.     /**
  109.      * Password
  110.      *
  111.      * @var string
  112.      *
  113.      * @ORM\Column (type="string")
  114.      */
  115.     protected $password '';
  116.     /**
  117.      * Password hint
  118.      *
  119.      * @var string
  120.      *
  121.      * @ORM\Column (type="string", length=128)
  122.      */
  123.     protected $password_hint '';
  124.     /**
  125.      * Password hint answer
  126.      *
  127.      * @var string
  128.      *
  129.      * @ORM\Column (type="string", length=128)
  130.      */
  131.     protected $password_hint_answer '';
  132.     /**
  133.      * Password reset key (for 'Forgot password')
  134.      *
  135.      * @var string
  136.      *
  137.      * @ORM\Column (type="string")
  138.      */
  139.     protected $passwordResetKey '';
  140.     /**
  141.      * Timestamp of reset key creation date
  142.      *
  143.      * @var integer
  144.      *
  145.      * @ORM\Column (type="integer")
  146.      */
  147.     protected $passwordResetKeyDate 0;
  148.     /**
  149.      * Access level
  150.      *
  151.      * @var integer
  152.      *
  153.      * @ORM\Column (type="integer")
  154.      */
  155.     protected $access_level 0;
  156.     /**
  157.      * Timestamp of profile creation date
  158.      *
  159.      * @var integer
  160.      *
  161.      * @ORM\Column (type="integer")
  162.      */
  163.     protected $added 0;
  164.     /**
  165.      * Timestamp of first login event
  166.      *
  167.      * @var integer
  168.      *
  169.      * @ORM\Column (type="integer")
  170.      */
  171.     protected $first_login 0;
  172.     /**
  173.      * Timestamp of last login event
  174.      *
  175.      * @var integer
  176.      *
  177.      * @ORM\Column (type="integer")
  178.      */
  179.     protected $last_login 0;
  180.     /**
  181.      * Profile status
  182.      *
  183.      * @var string
  184.      *
  185.      * @ORM\Column (type="string", options={ "fixed": true }, length=1)
  186.      */
  187.     protected $status self::STATUS_ENABLED;
  188.     /**
  189.      * Status comment (reason)
  190.      *
  191.      * @var string
  192.      *
  193.      * @ORM\Column (type="string", length=255)
  194.      */
  195.     protected $statusComment '';
  196.     /**
  197.      * Referer
  198.      *
  199.      * @var string
  200.      *
  201.      * @ORM\Column (type="string", length=255)
  202.      */
  203.     protected $referer '';
  204.     /**
  205.      * Relation to an order
  206.      *
  207.      * @var Order
  208.      *
  209.      * @ORM\OneToOne   (targetEntity="XLite\Model\Order")
  210.      * @ORM\JoinColumn (name="order_id", referencedColumnName="order_id", onDelete="CASCADE")
  211.      */
  212.     protected $order;
  213.     /**
  214.      * Relation to an event
  215.      *
  216.      * @var OrderHistoryEvents
  217.      *
  218.      * @ORM\OneToMany   (targetEntity="XLite\Model\OrderHistoryEvents", mappedBy="author")
  219.      * @ORM\JoinColumn (name="event_id", referencedColumnName="event_id", onDelete="CASCADE")
  220.      */
  221.     protected $event;
  222.     /**
  223.      * Language code
  224.      *
  225.      * @var string
  226.      *
  227.      * @ORM\Column (type="string", length=2)
  228.      */
  229.     protected $language '';
  230.     /**
  231.      * Last selected shipping id
  232.      *
  233.      * @var integer
  234.      *
  235.      * @ORM\Column (type="integer", nullable=true)
  236.      */
  237.     protected $last_shipping_id;
  238.     /**
  239.      * Last selected payment id
  240.      *
  241.      * @var integer
  242.      *
  243.      * @ORM\Column (type="integer", nullable=true)
  244.      */
  245.     protected $last_payment_id;
  246.     /**
  247.      * Membership: many-to-one relation with memberships table
  248.      *
  249.      * @var Membership
  250.      *
  251.      * @ORM\ManyToOne  (targetEntity="XLite\Model\Membership")
  252.      * @ORM\JoinColumn (name="membership_id", referencedColumnName="membership_id", onDelete="SET NULL")
  253.      */
  254.     protected $membership;
  255.     /**
  256.      * Pending membership: many-to-one relation with memberships table
  257.      *
  258.      * @var Membership
  259.      *
  260.      * @ORM\ManyToOne  (targetEntity="XLite\Model\Membership")
  261.      * @ORM\JoinColumn (name="pending_membership_id", referencedColumnName="membership_id", onDelete="SET NULL")
  262.      */
  263.     protected $pending_membership;
  264.     /**
  265.      * Address book: one-to-many relation with address book entity
  266.      *
  267.      * @var \Doctrine\Common\Collections\ArrayCollection
  268.      *
  269.      * @ORM\OneToMany (targetEntity="XLite\Model\Address", mappedBy="profile", cascade={"all"})
  270.      */
  271.     protected $addresses;
  272.     /**
  273.      * Roles
  274.      *
  275.      * @var \Doctrine\Common\Collections\Collection
  276.      *
  277.      * @ORM\ManyToMany (targetEntity="XLite\Model\Role", mappedBy="profiles", cascade={"merge","detach","persist"})
  278.      */
  279.     protected $roles;
  280.     /**
  281.      * The count of orders placed by the user
  282.      *
  283.      * @var integer
  284.      */
  285.     protected $orders_count null;
  286.     /**
  287.      * Flag of anonymous profile (used for checkout process only)
  288.      *
  289.      * @var boolean
  290.      *
  291.      * @ORM\Column (type="boolean")
  292.      */
  293.     protected $anonymous false;
  294.     /**
  295.      * Flag if the user needs to change the password.
  296.      * The customers only
  297.      *
  298.      * @var boolean
  299.      *
  300.      * @ORM\Column (type="boolean")
  301.      */
  302.     protected $forceChangePassword false;
  303.     /**
  304.      * Date of last login attempt
  305.      *
  306.      * @var integer
  307.      *
  308.      * @ORM\Column (type="integer", options={ "unsigned": true })
  309.      */
  310.     protected $dateOfLoginAttempt 0;
  311.     /**
  312.      * Count of login attempt
  313.      *
  314.      * @var integer
  315.      *
  316.      * @ORM\Column (type="integer")
  317.      */
  318.     protected $countOfLoginAttempts 0;
  319.     /**
  320.      * Fake field for search
  321.      *
  322.      * @var string
  323.      *
  324.      * @ORM\Column (type="text", nullable=true)
  325.      */
  326.     protected $searchFakeField;
  327.     /**
  328.      * Flag to exporting entities
  329.      *
  330.      * @var boolean
  331.      *
  332.      * @ORM\Column (type="boolean")
  333.      */
  334.     protected $xcPendingExport false;
  335.     /**
  336.      * Checkout email
  337.      *
  338.      * @var string
  339.      *
  340.      * @ORM\Column (type="string")
  341.      */
  342.     protected $lastCheckoutEmail '';
  343.     /**
  344.      * Set referer
  345.      *
  346.      * @param string $value Value
  347.      *
  348.      * @return void
  349.      */
  350.     public function setReferer(string $value)
  351.     {
  352.         $this->referer substr($value0255);
  353.     }
  354.     /**
  355.      * Set membership
  356.      *
  357.      * @param Membership|null $membership Membership OPTIONAL
  358.      *
  359.      * @return void
  360.      */
  361.     public function setMembership(Membership $membership null)
  362.     {
  363.         $this->membership $membership;
  364.     }
  365.     /**
  366.      * Set pending membership
  367.      *
  368.      * @param Membership|null $pendingMembership Pending membership OPTIONAL
  369.      *
  370.      * @return void
  371.      */
  372.     public function setPendingMembership(Membership $pendingMembership null)
  373.     {
  374.         $this->pending_membership $pendingMembership;
  375.     }
  376.     /**
  377.      * Get membership id
  378.      *
  379.      * @return integer
  380.      */
  381.     public function getMembershipId()
  382.     {
  383.         return $this->getMembership()?->getMembershipId();
  384.     }
  385.     /**
  386.      * Get pending membership id
  387.      *
  388.      * @return integer
  389.      */
  390.     public function getPendingMembershipId()
  391.     {
  392.         return $this->getPendingMembership()?->getMembershipId();
  393.     }
  394.     /**
  395.      * Get name
  396.      *
  397.      * @param boolean $useDefault Administrator|Customer if missing OPTIONAL
  398.      * @param boolean $shortName FirstName only OPTIONAL
  399.      *
  400.      * @return string
  401.      */
  402.     public function getName($useDefault true$shortName false)
  403.     {
  404.         $address $this->getBillingAddress() ?: $this->getShippingAddress();
  405.         if ($address) {
  406.             if ($shortName && $address->getFirstname()) {
  407.                 return trim($address->getFirstname());
  408.             } elseif ($address->getFirstname() || $address->getLastname()) {
  409.                 return trim($address->getFirstname() . ' ' $address->getLastname());
  410.             }
  411.         }
  412.         return $this->getNameFromDefaultAddress() ? $this->getNameFromDefaultAddress() : ($useDefault $this->getDefaultName() : '');
  413.     }
  414.     /**
  415.      * Get default name from address
  416.      *
  417.      * @return string
  418.      */
  419.     public function getNameFromDefaultAddress()
  420.     {
  421.         $result "";
  422.         if (count($this->getAddresses())) {
  423.             foreach ($this->getAddresses() as $address) {
  424.                 $result trim($address->getFirstname() . ' ' $address->getLastname());
  425.                 break;
  426.             }
  427.         }
  428.         return $result;
  429.     }
  430.     /**
  431.      * Get default name
  432.      *
  433.      * @return string
  434.      */
  435.     protected function getDefaultName()
  436.     {
  437.         return $this->isAdmin()
  438.             ? static::t('na_admin')
  439.             : static::t('na_customer');
  440.     }
  441.     /**
  442.      * Returns billing address
  443.      *
  444.      * @return Address
  445.      */
  446.     public function getBillingAddress()
  447.     {
  448.         return $this->getAddressByType(Address::BILLING);
  449.     }
  450.     /**
  451.      * Returns shipping address
  452.      *
  453.      * @return Address
  454.      */
  455.     public function getShippingAddress()
  456.     {
  457.         return $this->getAddressByType(Address::SHIPPING);
  458.     }
  459.     /**
  460.      * Switches current billing address to a new one
  461.      *
  462.      * @param Address $new
  463.      */
  464.     public function setBillingAddress($new)
  465.     {
  466.         $current $this->getBillingAddress();
  467.         if ($current && $current->getUniqueIdentifier() == $new->getUniqueIdentifier()) {
  468.             return;
  469.         }
  470.         $this->setAddress('billing'$new);
  471.     }
  472.     /**
  473.      * Switches current shipping address to a new one
  474.      *
  475.      * @param Address $new
  476.      */
  477.     public function setShippingAddress($new)
  478.     {
  479.         $current $this->getShippingAddress();
  480.         if ($current && $current->getUniqueIdentifier() == $new->getUniqueIdentifier()) {
  481.             return;
  482.         }
  483.         $this->setAddress('shipping'$new);
  484.     }
  485.     /**
  486.      * Set current address by type
  487.      *
  488.      * @param string  $type
  489.      * @param Address $new
  490.      */
  491.     protected function setAddress($type$new)
  492.     {
  493.         $current = ($type == 'shipping')
  494.             ? $this->getShippingAddress()
  495.             : $this->getBillingAddress();
  496.         if ($current && $current->getUniqueIdentifier() == $new->getUniqueIdentifier()) {
  497.             return;
  498.         }
  499.         $useAsOtherType \XLite\Core\Session::getInstance()->same_address ?? null;
  500.         // Disable current address
  501.         if ($current) {
  502.             if ($current->getIsWork()) {
  503.                 $this->getAddresses()->removeElement($current);
  504.                 \XLite\Core\Database::getEM()->remove($current);
  505.             }
  506.             $useAsOtherType = ($type == 'shipping')
  507.                 ? $current->getIsBilling()
  508.                 : $current->getIsShipping();
  509.             $current->setIsShipping(false);
  510.             $current->setIsBilling(false);
  511.         }
  512.         // Check if new address is not assigned to this profile
  513.         $addToProfile true;
  514.         foreach ($this->getAddresses() as $profileAddress) {
  515.             if ($profileAddress->getUniqueIdentifier() == $new->getUniqueIdentifier()) {
  516.                 $addToProfile false;
  517.             }
  518.         }
  519.         if ($addToProfile) {
  520.             $this->addAddresses($new);
  521.             $new->setProfile($this);
  522.         }
  523.         if ($type == 'shipping') {
  524.             $new->setIsShipping(true);
  525.             if ($useAsOtherType !== null && $current && !$current->getIsWork()) {
  526.                 $new->setIsBilling($useAsOtherType);
  527.             }
  528.         } else {
  529.             $new->setIsBilling(true);
  530.             if ($useAsOtherType !== null && $current && !$current->getIsWork()) {
  531.                 $new->setIsShipping($useAsOtherType);
  532.             }
  533.         }
  534.     }
  535.     /**
  536.      * Returns first available address
  537.      *
  538.      * @return Address
  539.      */
  540.     public function getFirstAddress()
  541.     {
  542.         $result null;
  543.         foreach ($this->getAddresses() as $address) {
  544.             $result $address;
  545.             break;
  546.         }
  547.         return $result;
  548.     }
  549.     /**
  550.      * Has tax exemption
  551.      *
  552.      * @return boolean
  553.      */
  554.     public function hasTaxExemption()
  555.     {
  556.         return false;
  557.     }
  558.     /**
  559.      * Returns the number of orders places by the user
  560.      *
  561.      * @return integer
  562.      */
  563.     public function getOrdersCount()
  564.     {
  565.         if ($this->orders_count === null) {
  566.             $cnd = new \XLite\Core\CommonCell();
  567.             $cnd->profile $this;
  568.             $this->orders_count \XLite\Core\Database::getRepo('XLite\Model\Order')->search($cndtrue);
  569.         }
  570.         return $this->orders_count;
  571.     }
  572.     /**
  573.      * Check if profile is enabled
  574.      *
  575.      * @return boolean
  576.      */
  577.     public function isEnabled()
  578.     {
  579.         return strtoupper($this->getStatus()) === static::STATUS_ENABLED;
  580.     }
  581.     /**
  582.      * Check if profile is disabled
  583.      *
  584.      * @return bool
  585.      */
  586.     public function isDisabled(): bool
  587.     {
  588.         return strtoupper($this->getStatus()) === static::STATUS_DISABLED;
  589.     }
  590.     /**
  591.      * Enable user profile
  592.      *
  593.      * @return void
  594.      */
  595.     public function enable()
  596.     {
  597.         $this->setStatus(static::STATUS_ENABLED);
  598.     }
  599.     /**
  600.      * Disable user profile
  601.      *
  602.      * @return void
  603.      */
  604.     public function disable()
  605.     {
  606.         $this->setStatus(static::STATUS_DISABLED);
  607.     }
  608.     /**
  609.      * Returns true if profile has an administrator access level
  610.      *
  611.      * @return boolean
  612.      */
  613.     public function isAdmin()
  614.     {
  615.         return $this->getAccessLevel() >= \XLite\Core\Auth::getInstance()->getAdminAccessLevel();
  616.     }
  617.     /**
  618.      * Create an entity profile in the database
  619.      *
  620.      * @return boolean
  621.      */
  622.     public function create()
  623.     {
  624.         $this->prepareCreate();
  625.         return parent::create();
  626.     }
  627.     /**
  628.      * Update an entity in the database
  629.      *
  630.      * @param boolean $cloneMode Clone mode OPTIONAL
  631.      *
  632.      * @return boolean
  633.      */
  634.     public function update($cloneMode false)
  635.     {
  636.         // Check if user with specified e-mail address is already exists
  637.         $exists $cloneMode
  638.             null
  639.             \XLite\Core\Database::getRepo('XLite\Model\Profile')->checkRegisteredUserWithSameLogin($this);
  640.         if ($exists) {
  641.             $this->addErrorEmailExists();
  642.             $result false;
  643.         } else {
  644.             $this->updateSearchFakeField();
  645.             // Do an entity update
  646.             $result parent::update();
  647.         }
  648.         return $result;
  649.     }
  650.     /**
  651.      * Delete an entity profile from the database
  652.      *
  653.      * @return boolean
  654.      */
  655.     public function delete()
  656.     {
  657.         // Check if the deleted profile is a last admin profile
  658.         if ($this->isAdmin() && \XLite\Core\Database::getRepo('XLite\Model\Profile')->findCountOfAdminAccounts() == 1) {
  659.             $result false;
  660.             \XLite\Core\TopMessage::addError('The only remaining active administrator profile cannot be deleted.');
  661.         } else {
  662.             $result parent::delete();
  663.         }
  664.         return $result;
  665.     }
  666.     /**
  667.      * Check if billing and shipping addresses are equal or not
  668.      *
  669.      * @return boolean
  670.      */
  671.     public function isSameAddress()
  672.     {
  673.         $result false;
  674.         $billingAddress $this->getBillingAddress();
  675.         $shippingAddress $this->getShippingAddress();
  676.         if ($billingAddress !== null && $shippingAddress !== null) {
  677.             $result true;
  678.             if ($billingAddress->getAddressId() != $shippingAddress->getAddressId()) {
  679.                 $addressFields $billingAddress->getAvailableAddressFields();
  680.                 foreach ($addressFields as $name) {
  681.                     $methodName 'get' \Includes\Utils\Converter::convertToUpperCamelCase($name);
  682.                     // Compare field values of billing and shipping addresses
  683.                     if ($billingAddress->$methodName() != $shippingAddress->$methodName()) {
  684.                         $result false;
  685.                         break;
  686.                     }
  687.                 }
  688.             }
  689.         }
  690.         return $result;
  691.     }
  692.     /**
  693.      * Check - billing and shipping addresses are equal or not
  694.      *
  695.      * @param boolean $strict Flag: true - both billing and shipping addresses must be defined OPTIONAL
  696.      *
  697.      * @return boolean
  698.      */
  699.     public function isEqualAddress($strict false)
  700.     {
  701.         $billingAddress $this->getBillingAddress();
  702.         $shippingAddress $this->getShippingAddress();
  703.         $result $billingAddress !== null && $shippingAddress !== null;
  704.         return $strict
  705.             $result && $billingAddress->getAddressId() == $shippingAddress->getAddressId()
  706.             : !$result || $billingAddress->getAddressId() == $shippingAddress->getAddressId();
  707.     }
  708.     /**
  709.      * Clone
  710.      *
  711.      * @return Profile
  712.      */
  713.     public function cloneEntity()
  714.     {
  715.         $newProfile parent::cloneEntity();
  716.         $newProfile->setMembership($this->getMembership());
  717.         $newProfile->setPendingMembership($this->getPendingMembership());
  718.         $newProfile->setPassword('');
  719.         $billingAddress $this->getBillingAddress();
  720.         if ($billingAddress !== null) {
  721.             $newBillingAddress $billingAddress->cloneEntity();
  722.             $newBillingAddress->setProfile($newProfile);
  723.             $newProfile->addAddresses($newBillingAddress);
  724.         }
  725.         $shippingAddress $this->getShippingAddress();
  726.         if (
  727.             $shippingAddress
  728.             && (!$billingAddress
  729.                 || $billingAddress->getAddressId() != $shippingAddress->getAddressId()
  730.                 || $billingAddress->getAddressId() === null
  731.                 || $shippingAddress->getAddressId() === null
  732.             )
  733.         ) {
  734.             $newShippingAddress $shippingAddress->cloneEntity();
  735.             $newShippingAddress->setProfile($newProfile);
  736.             $newProfile->addAddresses($newShippingAddress);
  737.         }
  738.         return $newProfile;
  739.     }
  740.     /**
  741.      * Constructor
  742.      *
  743.      * @param array $data Entity properties OPTIONAL
  744.      */
  745.     public function __construct(array $data = [])
  746.     {
  747.         $this->addresses = new \Doctrine\Common\Collections\ArrayCollection();
  748.         $this->roles     = new \Doctrine\Common\Collections\ArrayCollection();
  749.         parent::__construct($data);
  750.     }
  751.     /**
  752.      * Get language code
  753.      *
  754.      * @param boolean $isCreateMode Flag to get original entity language OPTIONAL
  755.      *
  756.      * @return string
  757.      */
  758.     public function getLanguage($isCreateMode false)
  759.     {
  760.         return $isCreateMode
  761.             $this->getLanguageForCreateProfile()
  762.             : $this->checkForActiveLanguage($this->language);
  763.     }
  764.     /**
  765.      * Define the language code for created profile
  766.      *
  767.      * @return string
  768.      */
  769.     protected function getLanguageForCreateProfile()
  770.     {
  771.         return $this->language;
  772.     }
  773.     /**
  774.      * Check if the language code is in the active languages list
  775.      * If customer language is not used right now, the default customer language code is used
  776.      *
  777.      * @param string $languageCode Language code
  778.      *
  779.      * @return string
  780.      */
  781.     protected function checkForActiveLanguage($languageCode)
  782.     {
  783.         $result $languageCode;
  784.         $langs \XLite\Core\Database::getRepo('XLite\Model\Language')->findActiveLanguages();
  785.         if (!empty($langs)) {
  786.             $resultModel \Includes\Utils\ArrayManager::searchInObjectsArray(
  787.                 $langs,
  788.                 'getCode',
  789.                 $result
  790.             );
  791.             if ($resultModel === null) {
  792.                 $result \XLite\Core\Config::getInstance()->General->default_language;
  793.             }
  794.         }
  795.         return $result;
  796.     }
  797.     /**
  798.      * Set order
  799.      *
  800.      * @param Order $order Order OPTIONAL
  801.      *
  802.      * @return void
  803.      */
  804.     public function setOrder(Order $order null)
  805.     {
  806.         $this->order $order;
  807.     }
  808.     /**
  809.      * Get password hash algorithm
  810.      *
  811.      * @return string
  812.      */
  813.     public function getPasswordAlgo()
  814.     {
  815.         $parts explode(':'$this->getPassword(), 2);
  816.         return count($parts) === 'MD5' $parts[0];
  817.     }
  818.     /**
  819.      * Merge profile with another profile
  820.      *
  821.      * @param Profile $profile Profile
  822.      * @param integer $flag    Operation flag OPTIONAL
  823.      *
  824.      * @return integer
  825.      */
  826.     public function mergeWithProfile(Profile $profile$flag self::MERGE_ALL)
  827.     {
  828.         $result 0;
  829.         // Addresses
  830.         if ($flag & static::MERGE_ADDRESSES) {
  831.             foreach ($profile->getAddresses() as $address) {
  832.                 $found false;
  833.                 foreach ($this->getAddresses() as $a) {
  834.                     if ($a->isEqualAddress($address)) {
  835.                         $found true;
  836.                         break;
  837.                     }
  838.                 }
  839.                 if (!$found) {
  840.                     $address $address->cloneEntity();
  841.                     $this->addAddresses($address);
  842.                     $address->setProfile($this);
  843.                 }
  844.             }
  845.             $result |= static::MERGE_ADDRESSES;
  846.         }
  847.         // Orders
  848.         if ($flag & static::MERGE_ORDERS) {
  849.             $cnd = new \XLite\Core\CommonCell();
  850.             $cnd->profile $profile;
  851.             foreach (\XLite\Core\Database::getRepo('XLite\Model\Order')->search($cnd) as $order) {
  852.                 $order->setOrigProfile($this);
  853.             }
  854.             $result |= static::MERGE_ORDERS;
  855.         }
  856.         return $result;
  857.     }
  858.     /**
  859.      * Prepare object for its creation in the database
  860.      *
  861.      * @return void
  862.      */
  863.     protected function prepareCreate()
  864.     {
  865.     }
  866.     /**
  867.      * Update field for search optimization
  868.      *
  869.      * @return void
  870.      */
  871.     public function updateSearchFakeField()
  872.     {
  873.         $searchFakeFieldParts = [];
  874.         foreach ($this->getAddresses() as $address) {
  875.             $searchFakeFieldParts[] = trim($address->getFirstname() . ' ' $address->getLastname() . ' ' $address->getFirstname());
  876.         }
  877.         $searchFakeFieldParts[] = $this->getLogin();
  878.         $this->setSearchFakeField(implode(';'$searchFakeFieldParts));
  879.     }
  880.     /**
  881.      * Returns address by its type (shipping or billing)
  882.      *
  883.      * @param string $atype Address type: b - billing, s - shipping OPTIONAL
  884.      *
  885.      * @return Address
  886.      */
  887.     protected function getAddressByType($atype Address::BILLING)
  888.     {
  889.         $result null;
  890.         foreach ($this->getAddresses() ?: [] as $address) {
  891.             if (
  892.                 ($atype === Address::BILLING && $address->getIsBilling())
  893.                 || ($atype === Address::SHIPPING && $address->getIsShipping())
  894.             ) {
  895.                 // Select address if its type is same as a requested type...
  896.                 $result $address;
  897.                 break;
  898.             }
  899.         }
  900.         return $result;
  901.     }
  902.     /**
  903.      * Add error top message 'Email already exists...'
  904.      *
  905.      * @return void
  906.      */
  907.     protected function addErrorEmailExists()
  908.     {
  909.         \XLite\Core\TopMessage::addError('This e-mail address is already in use by another user.');
  910.     }
  911.     // {{{ Roles
  912.     /**
  913.      * Check - specified permission is allowed or not
  914.      *
  915.      * @param string $code Permission code
  916.      *
  917.      * @return boolean
  918.      */
  919.     public function isPermissionAllowed($code)
  920.     {
  921.         $result false;
  922.         if (count($this->getRoles())) {
  923.             foreach ($this->getRoles() as $role) {
  924.                 if ($role->isPermissionAllowed($code)) {
  925.                     $result true;
  926.                     break;
  927.                 }
  928.             }
  929.         } elseif (\XLite\Core\Database::getRepo('XLite\Model\Role')->count() === 0) {
  930.             $result true;
  931.         }
  932.         return $result;
  933.     }
  934.     // }}}
  935.     /**
  936.      * Get profile_id
  937.      *
  938.      * @return integer
  939.      */
  940.     public function getProfileId(): ?int
  941.     {
  942.         return $this->profile_id;
  943.     }
  944.     public function setProfileId(int $profileId): static
  945.     {
  946.         $this->profile_id $profileId;
  947.         return $this;
  948.     }
  949.     /**
  950.      * Set login
  951.      *
  952.      * @param string $login
  953.      * @return Profile
  954.      */
  955.     public function setLogin($login)
  956.     {
  957.         $this->oldLogin $this->login;
  958.         $this->login $login;
  959.         return $this;
  960.     }
  961.     /**
  962.      * Get oldLogin
  963.      *
  964.      * @return string
  965.      */
  966.     public function getOldLogin()
  967.     {
  968.         return $this->oldLogin;
  969.     }
  970.     /**
  971.      * Get login
  972.      *
  973.      * @return string
  974.      */
  975.     public function getLogin(): string
  976.     {
  977.         return $this->login;
  978.     }
  979.     /**
  980.      * Set password
  981.      *
  982.      * @param string $password
  983.      * @return Profile
  984.      */
  985.     public function setPassword($password)
  986.     {
  987.         $this->password $password;
  988.         return $this;
  989.     }
  990.     /**
  991.      * Get password
  992.      *
  993.      * @return string
  994.      */
  995.     public function getPassword()
  996.     {
  997.         return $this->password;
  998.     }
  999.     /**
  1000.      * Set password_hint
  1001.      *
  1002.      * @param string $passwordHint
  1003.      * @return Profile
  1004.      */
  1005.     public function setPasswordHint($passwordHint)
  1006.     {
  1007.         $this->password_hint $passwordHint;
  1008.         return $this;
  1009.     }
  1010.     /**
  1011.      * Get password_hint
  1012.      *
  1013.      * @return string
  1014.      */
  1015.     public function getPasswordHint()
  1016.     {
  1017.         return $this->password_hint;
  1018.     }
  1019.     /**
  1020.      * Set password_hint_answer
  1021.      *
  1022.      * @param string $passwordHintAnswer
  1023.      * @return Profile
  1024.      */
  1025.     public function setPasswordHintAnswer($passwordHintAnswer)
  1026.     {
  1027.         $this->password_hint_answer $passwordHintAnswer;
  1028.         return $this;
  1029.     }
  1030.     /**
  1031.      * Get password_hint_answer
  1032.      *
  1033.      * @return string
  1034.      */
  1035.     public function getPasswordHintAnswer()
  1036.     {
  1037.         return $this->password_hint_answer;
  1038.     }
  1039.     /**
  1040.      * Set passwordResetKey
  1041.      *
  1042.      * @param string $passwordResetKey
  1043.      * @return Profile
  1044.      */
  1045.     public function setPasswordResetKey($passwordResetKey)
  1046.     {
  1047.         $this->passwordResetKey $passwordResetKey;
  1048.         return $this;
  1049.     }
  1050.     /**
  1051.      * Get passwordResetKey
  1052.      *
  1053.      * @return string
  1054.      */
  1055.     public function getPasswordResetKey()
  1056.     {
  1057.         return $this->passwordResetKey;
  1058.     }
  1059.     /**
  1060.      * Set passwordResetKeyDate
  1061.      *
  1062.      * @param integer $passwordResetKeyDate
  1063.      * @return Profile
  1064.      */
  1065.     public function setPasswordResetKeyDate($passwordResetKeyDate)
  1066.     {
  1067.         $this->passwordResetKeyDate $passwordResetKeyDate;
  1068.         return $this;
  1069.     }
  1070.     /**
  1071.      * Get passwordResetKeyDate
  1072.      *
  1073.      * @return integer
  1074.      */
  1075.     public function getPasswordResetKeyDate()
  1076.     {
  1077.         return $this->passwordResetKeyDate;
  1078.     }
  1079.     /**
  1080.      * Set access_level
  1081.      *
  1082.      * @param integer $accessLevel
  1083.      * @return Profile
  1084.      */
  1085.     public function setAccessLevel($accessLevel)
  1086.     {
  1087.         $this->access_level $accessLevel;
  1088.         return $this;
  1089.     }
  1090.     /**
  1091.      * Get access_level
  1092.      *
  1093.      * @return integer
  1094.      */
  1095.     public function getAccessLevel()
  1096.     {
  1097.         return $this->access_level;
  1098.     }
  1099.     /**
  1100.      * Set added
  1101.      *
  1102.      * @param integer $added
  1103.      * @return Profile
  1104.      */
  1105.     public function setAdded($added)
  1106.     {
  1107.         $this->added $added;
  1108.         return $this;
  1109.     }
  1110.     /**
  1111.      * Get added
  1112.      *
  1113.      * @return integer
  1114.      */
  1115.     public function getAdded()
  1116.     {
  1117.         return $this->added;
  1118.     }
  1119.     /**
  1120.      * Set first_login
  1121.      *
  1122.      * @param integer $firstLogin
  1123.      * @return Profile
  1124.      */
  1125.     public function setFirstLogin($firstLogin)
  1126.     {
  1127.         $this->first_login $firstLogin;
  1128.         return $this;
  1129.     }
  1130.     /**
  1131.      * Get first_login
  1132.      *
  1133.      * @return integer
  1134.      */
  1135.     public function getFirstLogin()
  1136.     {
  1137.         return $this->first_login;
  1138.     }
  1139.     /**
  1140.      * Set last_login
  1141.      *
  1142.      * @param integer $lastLogin
  1143.      * @return Profile
  1144.      */
  1145.     public function setLastLogin($lastLogin)
  1146.     {
  1147.         $this->last_login $lastLogin;
  1148.         return $this;
  1149.     }
  1150.     /**
  1151.      * Get last_login
  1152.      *
  1153.      * @return integer
  1154.      */
  1155.     public function getLastLogin()
  1156.     {
  1157.         return $this->last_login;
  1158.     }
  1159.     /**
  1160.      * Set status
  1161.      *
  1162.      * @param string $status
  1163.      * @return Profile
  1164.      */
  1165.     public function setStatus($status)
  1166.     {
  1167.         $this->status $status;
  1168.         return $this;
  1169.     }
  1170.     /**
  1171.      * Get status
  1172.      *
  1173.      * @return string
  1174.      */
  1175.     public function getStatus()
  1176.     {
  1177.         return $this->status;
  1178.     }
  1179.     /**
  1180.      * Set statusComment
  1181.      *
  1182.      * @param string $statusComment
  1183.      * @return Profile
  1184.      */
  1185.     public function setStatusComment($statusComment)
  1186.     {
  1187.         $this->statusComment $statusComment;
  1188.         return $this;
  1189.     }
  1190.     /**
  1191.      * Get statusComment
  1192.      *
  1193.      * @return string
  1194.      */
  1195.     public function getStatusComment()
  1196.     {
  1197.         return $this->statusComment;
  1198.     }
  1199.     /**
  1200.      * Get referer
  1201.      *
  1202.      * @return string
  1203.      */
  1204.     public function getReferer()
  1205.     {
  1206.         return $this->referer;
  1207.     }
  1208.     /**
  1209.      * Set language
  1210.      *
  1211.      * @param string $language
  1212.      * @return Profile
  1213.      */
  1214.     public function setLanguage($language)
  1215.     {
  1216.         $this->language $language;
  1217.         return $this;
  1218.     }
  1219.     /**
  1220.      * Set last_shipping_id
  1221.      *
  1222.      * @param integer $lastShippingId
  1223.      * @return Profile
  1224.      */
  1225.     public function setLastShippingId($lastShippingId)
  1226.     {
  1227.         $this->last_shipping_id $lastShippingId;
  1228.         return $this;
  1229.     }
  1230.     /**
  1231.      * Get last_shipping_id
  1232.      *
  1233.      * @return integer
  1234.      */
  1235.     public function getLastShippingId()
  1236.     {
  1237.         return $this->last_shipping_id;
  1238.     }
  1239.     /**
  1240.      * Set last_payment_id
  1241.      *
  1242.      * @param integer $lastPaymentId
  1243.      * @return Profile
  1244.      */
  1245.     public function setLastPaymentId($lastPaymentId)
  1246.     {
  1247.         $this->last_payment_id $lastPaymentId;
  1248.         return $this;
  1249.     }
  1250.     /**
  1251.      * Get last_payment_id
  1252.      *
  1253.      * @return integer
  1254.      */
  1255.     public function getLastPaymentId()
  1256.     {
  1257.         return $this->last_payment_id;
  1258.     }
  1259.     /**
  1260.      * Set anonymous
  1261.      *
  1262.      * @param boolean $anonymous
  1263.      * @return Profile
  1264.      */
  1265.     public function setAnonymous($anonymous)
  1266.     {
  1267.         $this->anonymous $anonymous;
  1268.         return $this;
  1269.     }
  1270.     /**
  1271.      * Get anonymous
  1272.      *
  1273.      * @return boolean
  1274.      */
  1275.     public function getAnonymous()
  1276.     {
  1277.         return $this->anonymous;
  1278.     }
  1279.     /**
  1280.      * Set forceChangePassword
  1281.      *
  1282.      * @param boolean $forceChangePassword
  1283.      * @return Profile
  1284.      */
  1285.     public function setForceChangePassword($forceChangePassword)
  1286.     {
  1287.         $this->forceChangePassword $forceChangePassword;
  1288.         return $this;
  1289.     }
  1290.     /**
  1291.      * Get forceChangePassword
  1292.      *
  1293.      * @return boolean
  1294.      */
  1295.     public function getForceChangePassword()
  1296.     {
  1297.         return $this->forceChangePassword;
  1298.     }
  1299.     /**
  1300.      * Set dateOfLoginAttempt
  1301.      *
  1302.      * @param integer $dateOfLoginAttempt
  1303.      * @return Profile
  1304.      */
  1305.     public function setDateOfLoginAttempt($dateOfLoginAttempt)
  1306.     {
  1307.         $this->dateOfLoginAttempt $dateOfLoginAttempt;
  1308.         return $this;
  1309.     }
  1310.     /**
  1311.      * Get dateOfLoginAttempt
  1312.      *
  1313.      * @return integer
  1314.      */
  1315.     public function getDateOfLoginAttempt()
  1316.     {
  1317.         return $this->dateOfLoginAttempt;
  1318.     }
  1319.     /**
  1320.      * Set countOfLoginAttempts
  1321.      *
  1322.      * @param integer $countOfLoginAttempts
  1323.      * @return Profile
  1324.      */
  1325.     public function setCountOfLoginAttempts($countOfLoginAttempts)
  1326.     {
  1327.         $this->countOfLoginAttempts $countOfLoginAttempts;
  1328.         return $this;
  1329.     }
  1330.     /**
  1331.      * Get countOfLoginAttempts
  1332.      *
  1333.      * @return integer
  1334.      */
  1335.     public function getCountOfLoginAttempts()
  1336.     {
  1337.         return $this->countOfLoginAttempts;
  1338.     }
  1339.     /**
  1340.      * Set searchFakeField
  1341.      *
  1342.      * @param string $searchFakeField
  1343.      * @return Profile
  1344.      */
  1345.     public function setSearchFakeField($searchFakeField)
  1346.     {
  1347.         $this->searchFakeField $searchFakeField;
  1348.         return $this;
  1349.     }
  1350.     /**
  1351.      * Get searchFakeField
  1352.      *
  1353.      * @return string
  1354.      */
  1355.     public function getSearchFakeField()
  1356.     {
  1357.         return $this->searchFakeField;
  1358.     }
  1359.     /**
  1360.      * Set xcPendingExport
  1361.      *
  1362.      * @param boolean $xcPendingExport
  1363.      * @return Profile
  1364.      */
  1365.     public function setXcPendingExport($xcPendingExport)
  1366.     {
  1367.         $this->xcPendingExport $xcPendingExport;
  1368.         return $this;
  1369.     }
  1370.     /**
  1371.      * Get xcPendingExport
  1372.      *
  1373.      * @return boolean
  1374.      */
  1375.     public function getXcPendingExport()
  1376.     {
  1377.         return $this->xcPendingExport;
  1378.     }
  1379.     /**
  1380.      * Get order
  1381.      *
  1382.      * @return Order
  1383.      */
  1384.     public function getOrder()
  1385.     {
  1386.         return $this->order;
  1387.     }
  1388.     /**
  1389.      * Add event
  1390.      *
  1391.      * @param OrderHistoryEvents $event
  1392.      *
  1393.      * @return Profile
  1394.      */
  1395.     public function addEvent(OrderHistoryEvents $event)
  1396.     {
  1397.         $this->event[] = $event;
  1398.         return $this;
  1399.     }
  1400.     /**
  1401.      * Get event
  1402.      *
  1403.      * @return OrderHistoryEvents
  1404.      */
  1405.     public function getEvent()
  1406.     {
  1407.         return $this->event;
  1408.     }
  1409.     /**
  1410.      * Get membership
  1411.      *
  1412.      * @return Membership
  1413.      */
  1414.     public function getMembership()
  1415.     {
  1416.         return $this->membership;
  1417.     }
  1418.     /**
  1419.      * Get pending_membership
  1420.      *
  1421.      * @return Membership
  1422.      */
  1423.     public function getPendingMembership()
  1424.     {
  1425.         return $this->pending_membership;
  1426.     }
  1427.     /**
  1428.      * Add addresses
  1429.      *
  1430.      * @param Address $addresses
  1431.      *
  1432.      * @return Profile
  1433.      */
  1434.     public function addAddresses(Address $addresses)
  1435.     {
  1436.         $this->addresses[] = $addresses;
  1437.         return $this;
  1438.     }
  1439.     /**
  1440.      * Get addresses
  1441.      *
  1442.      * @return \Doctrine\Common\Collections\Collection
  1443.      */
  1444.     public function getAddresses()
  1445.     {
  1446.         return $this->addresses;
  1447.     }
  1448.     /**
  1449.      * Add roles
  1450.      *
  1451.      * @param \XLite\Model\Role $roles
  1452.      * @return Profile
  1453.      */
  1454.     public function addRoles(\XLite\Model\Role $roles)
  1455.     {
  1456.         $this->roles[] = $roles;
  1457.         return $this;
  1458.     }
  1459.     /**
  1460.      * Get roles
  1461.      *
  1462.      * @return \Doctrine\Common\Collections\ArrayCollection|\Doctrine\Common\Collections\Collection
  1463.      */
  1464.     public function getRoles()
  1465.     {
  1466.         return $this->roles;
  1467.     }
  1468.     /**
  1469.      * @return string
  1470.      */
  1471.     public function getEmail()
  1472.     {
  1473.         return $this->getLastCheckoutEmail()
  1474.             ?: $this->getLogin();
  1475.     }
  1476.     /**
  1477.      * @return string
  1478.      */
  1479.     public function getLastCheckoutEmail()
  1480.     {
  1481.         return $this->lastCheckoutEmail;
  1482.     }
  1483.     /**
  1484.      * @param string $lastCheckoutEmail
  1485.      *
  1486.      * @return $this
  1487.      */
  1488.     public function setLastCheckoutEmail($lastCheckoutEmail)
  1489.     {
  1490.         $this->lastCheckoutEmail $lastCheckoutEmail;
  1491.         return $this;
  1492.     }
  1493.     /**
  1494.      * @return string
  1495.      */
  1496.     public function getSalt(): string
  1497.     {
  1498.         return implode('', [$this->login$this->password]);
  1499.     }
  1500.     public static function isAppropriatePasswordLength(string $password): bool
  1501.     {
  1502.         $passwordLength strlen($password);
  1503.         return ($passwordLength >= static::MIN_PASSWORD_LENGTH) && ($passwordLength <= static::MAX_PASSWORD_LENGTH);
  1504.     }
  1505.     public static function getPasswordLengthError(): string
  1506.     {
  1507.         return (string) Translation::lbl(
  1508.             'Password must be between X and Y characters long',
  1509.             [
  1510.                 'min_length' => static::MIN_PASSWORD_LENGTH,
  1511.                 'max_length' => static::MAX_PASSWORD_LENGTH
  1512.             ]
  1513.         );
  1514.     }
  1515. }