Completed
Push — master ( 3c661d...2a57f9 )
by Will
26s queued 12s
created

src/Checkout/Component/Membership.php (1 issue)

1
<?php
2
3
namespace SilverShop\Checkout\Component;
4
5
use SilverShop\Checkout\Checkout;
6
use SilverShop\Checkout\ShopMemberFactory;
7
use SilverShop\Extension\MemberExtension;
8
use SilverShop\Model\Order;
9
use SilverStripe\Core\Injector\Injector;
10
use SilverStripe\Forms\ConfirmedPasswordField;
11
use SilverStripe\Forms\FieldList;
12
use SilverStripe\Forms\Form;
13
use SilverStripe\Forms\PasswordField;
14
use SilverStripe\Forms\TextField;
15
use SilverStripe\ORM\ValidationException;
16
use SilverStripe\ORM\ValidationResult;
17
use SilverStripe\Security\IdentityStore;
18
use SilverStripe\Security\Member;
19
use SilverStripe\Security\PasswordValidator;
20
use SilverStripe\Security\Security;
21
22
/**
23
 * Provides:
24
 *    - member identifier, and password fields.
25
 *    - required membership fields
26
 *    - validating data
27
 */
28
class Membership extends CheckoutComponent
29
{
30
    protected $confirmed;
31
32
    protected $passwordvalidator;
33
34
    protected $dependson = [
35
        CustomerDetails::class,
36
    ];
37
38
    public function __construct($confirmed = true, $validator = null)
39
    {
40
        $this->confirmed = $confirmed;
41
        if (!$validator) {
42
            $this->passwordvalidator = Member::password_validator();
43
            if (!$this->passwordvalidator) {
44
                $this->passwordvalidator = PasswordValidator::create();
45
                $this->passwordvalidator->minLength(5);
46
                $this->passwordvalidator->characterStrength(
47
                    2,
48
                    ["lowercase", "uppercase", "digits", "punctuation"]
49
                );
50
            }
51
        }
52
    }
53
54
    public function getFormFields(Order $order, Form $form = null)
55
    {
56
        $fields = FieldList::create();
57
        if (Security::getCurrentUser()) {
58
            return $fields;
59
        }
60
        $idfield = Member::config()->unique_identifier_field;
61
        if (!$order->{$idfield} && ($form && !$form->Fields()->fieldByName($idfield))) {
62
            //TODO: scaffold the correct id field type
63
            $fields->push(TextField::create($idfield, $idfield));
64
        }
65
        $fields->push($this->getPasswordField());
66
        return $fields;
67
    }
68
69
    public function getRequiredFields(Order $order)
70
    {
71
        if (Security::getCurrentUser() || !Checkout::membership_required()) {
72
            return array();
73
        }
74
        return array(
75
            Member::config()->unique_identifier_field,
76
            'Password',
77
        );
78
    }
79
80
    public function getPasswordField()
81
    {
82
        if ($this->confirmed) {
83
            //relies on fix: https://github.com/silverstripe/silverstripe-framework/pull/2757
84
            return ConfirmedPasswordField::create('Password', _t('SilverShop\Checkout\CheckoutField.Password', 'Password'))
85
                ->setCanBeEmpty(!Checkout::membership_required());
86
        }
87
        return PasswordField::create('Password', _t('SilverShop\Checkout\CheckoutField.Password', 'Password'));
88
    }
89
90
    public function validateData(Order $order, array $data)
91
    {
92
        if (Security::getCurrentUser()) {
93
            return;
94
        }
95
        $result = ValidationResult::create();
96
        if (Checkout::membership_required() || !empty($data['Password'])) {
97
            $member = Member::create($data);
98
            $idfield = Member::config()->unique_identifier_field;
99
            $idval = $data[$idfield];
100
            if (MemberExtension::get_by_identifier($idval)) {
101
                // get localized field labels
102
                $fieldLabels = $member->fieldLabels(false);
103
                // if a localized value exists, use this for our error-message
104
                $fieldLabel = isset($fieldLabels[$idfield]) ? $fieldLabels[$idfield] : $idfield;
105
                $result->addError(
106
                    _t(
107
                        'SilverShop\Checkout\Checkout.MemberExists',
108
                        'A member already exists with the {Field} {Identifier}',
109
                        '',
110
                        array('Field' => $fieldLabel, 'Identifier' => $idval)
111
                    ),
112
                    $idfield
113
                );
114
            }
115
            $passwordresult = $this->passwordvalidator->validate($data['Password'], $member);
116
            if (!$passwordresult->isValid()) {
117
                foreach ($passwordresult->getMessages() as $message) {
118
                    $result->addError($message['message'], "Password");
119
                }
120
            }
121
        }
122
        if (!$result->isValid()) {
123
            throw new ValidationException($result);
124
        }
125
    }
126
127
    public function getData(Order $order)
128
    {
129
        $data = array();
130
131
        if ($member = Security::getCurrentUser()) {
132
            $idf = Member::config()->unique_identifier_field;
133
            $data[$idf] = $member->{$idf};
134
        }
135
        return $data;
136
    }
137
138
    /**
139
     * @throws ValidationException
140
     */
141
    public function setData(Order $order, array $data)
142
    {
143
        if (Security::getCurrentUser()) {
144
            return;
145
        }
146
        if (!Checkout::membership_required() && empty($data['Password'])) {
147
            return;
148
        }
149
150
        $factory = new ShopMemberFactory();
151
        $member = $factory->create($data);
152
        $member->write();
153
        // Log-in the current member
154
        Injector::inst()->get(IdentityStore::class)->logIn($member);
155
156
        if ($order->BillingAddressID) {
157
            $address = $order->getBillingAddress();
158
            $address->MemberID = $member->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property MemberID does not exist on SilverShop\Model\Address. Since you implemented __set, consider adding a @property annotation.
Loading history...
159
            $address->write();
160
            $member->DefaultBillingAddressID = $order->BillingAddressID;
161
        }
162
        if ($order->ShippingAddressID) {
163
            $address = $order->getShippingAddress();
164
            $address->MemberID = $member->ID;
165
            $address->write();
166
            $member->DefaultShippingAddressID = $order->ShippingAddressID;
167
        }
168
        if ($member->isChanged()) {
169
            $member->write();
170
        }
171
    }
172
173
    public function setConfirmed($confirmed)
174
    {
175
        $this->confirmed = $confirmed;
176
177
        return $this;
178
    }
179
}
180