Completed
Pull Request — 2.0 (#506)
by Roman
18:39
created

MembershipCheckoutComponent   B

Complexity

Total Complexity 31

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 15

Test Coverage

Coverage 58.16%

Importance

Changes 5
Bugs 1 Features 2
Metric Value
wmc 31
c 5
b 1
f 2
lcom 2
cbo 15
dl 0
loc 149
ccs 57
cts 98
cp 0.5816
rs 8.9833

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 3
B getFormFields() 0 14 5
A getRequiredFields() 0 10 3
A getPasswordField() 0 9 2
A getData() 0 10 2
C setData() 0 30 7
A setConfirmed() 0 6 1
C validateData() 0 34 8
1
<?php
2
3
/**
4
 * Provides:
5
 *    - member identifier, and password fields.
6
 *    - required membership fields
7
 *    - validating data
8
 *
9
 */
10
class MembershipCheckoutComponent extends CheckoutComponent
11
{
12
    protected $confirmed;
13
14
    protected $passwordvalidator;
15
16
    protected $dependson = array(
17
        'CustomerDetailsCheckoutComponent',
18
    );
19
20 1
    public function __construct($confirmed = true, $validator = null)
21
    {
22 1
        $this->confirmed = $confirmed;
23 1
        if (!$validator) {
24 1
            $this->passwordvalidator = Member::password_validator();
25 1
            if (!$this->passwordvalidator) {
26 1
                $this->passwordvalidator = PasswordValidator::create();
27 1
                $this->passwordvalidator->minLength(5);
28 1
                $this->passwordvalidator->characterStrength(
29 1
                    2,
30 1
                    array("lowercase", "uppercase", "digits", "punctuation")
31 1
                );
32 1
            }
33 1
        }
34 1
    }
35
36 1
    public function getFormFields(Order $order, Form $form = null)
37
    {
38 1
        $fields = FieldList::create();
39 1
        if (Member::currentUserID()) {
40
            return $fields;
41
        }
42 1
        $idfield = Member::config()->unique_identifier_field;
43 1
        if (!$order->{$idfield} && ($form && !$form->Fields()->fieldByName($idfield))) {
44
            //TODO: scaffold the correct id field type
45
            $fields->push(TextField::create($idfield, $idfield));
46
        }
47 1
        $fields->push($this->getPasswordField());
48 1
        return $fields;
49
    }
50
51 1
    public function getRequiredFields(Order $order)
52
    {
53 1
        if (Member::currentUserID() || !Checkout::membership_required()) {
54 1
            return array();
55
        }
56
        return array(
57
            Member::config()->unique_identifier_field,
58
            'Password',
59
        );
60
    }
61
62 1
    public function getPasswordField()
63
    {
64 1
        if ($this->confirmed) {
65
            //relies on fix: https://github.com/silverstripe/silverstripe-framework/pull/2757
66 1
            return ConfirmedPasswordField::create('Password', _t('CheckoutField.Password', 'Password'))
67 1
                ->setCanBeEmpty(!Checkout::membership_required());
68
        }
69
        return PasswordField::create('Password', _t('CheckoutField.Password', 'Password'));
70
    }
71
72 1
    public function validateData(Order $order, array $data)
73
    {
74 1
        if (Member::currentUserID()) {
75
            return;
76
        }
77 1
        $result = ValidationResult::create();
78 1
        if (Checkout::membership_required() || !empty($data['Password'])) {
79 1
            $member = Member::create($data);
80 1
            $idfield = Member::config()->unique_identifier_field;
81 1
            $idval = $data[$idfield];
82 1
            if (ShopMember::get_by_identifier($idval)) {
83
                // get localized field labels
84
                $fieldLabels = $member->fieldLabels(false);
85
                // if a localized value exists, use this for our error-message
86 1
                $fieldLabel = isset($fieldLabels[$idfield]) ? $fieldLabels[$idfield] : $idfield;
87
                $result->error(
88
                    _t(
89
                        'Checkout.MemberExists',
90
                        'A member already exists with the {Field} {Identifier}',
91
                        '',
92
                        array('Field' => $fieldLabel, 'Identifier' => $idval)
0 ignored issues
show
Documentation introduced by
array('Field' => $fieldL...'Identifier' => $idval) is of type array<string,?,{"Field":"?","Identifier":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
93
                    ),
94
                    $idfield
95
                );
96
            }
97 1
            $passwordresult = $this->passwordvalidator->validate($data['Password'], $member);
98 1
            if (!$passwordresult->valid()) {
99
                $result->error($passwordresult->message(), "Password");
100
            }
101 1
        }
102 1
        if (!$result->valid()) {
103
            throw new ValidationException($result);
104
        }
105 1
    }
106
107 1
    public function getData(Order $order)
108
    {
109 1
        $data = array();
110
111 1
        if ($member = Member::currentUser()) {
112
            $idf = Member::config()->unique_identifier_field;
113
            $data[$idf] = $member->{$idf};
114
        }
115 1
        return $data;
116
    }
117
118
    /**
119
     * @throws ValidationException
120
     */
121 1
    public function setData(Order $order, array $data)
122
    {
123 1
        if (Member::currentUserID()) {
124
            return;
125
        }
126 1
        if (!Checkout::membership_required() && empty($data['Password'])) {
127
            return;
128
        }
129
130 1
        $factory = new ShopMemberFactory();
131 1
        $member = $factory->create($data);
132 1
        $member->write();
133 1
        $member->logIn();
134
135 1
        if ($order->BillingAddressID) {
136
            $address = $order->getBillingAddress();
137
            $address->MemberID = $member->ID;
0 ignored issues
show
Documentation introduced by
The property MemberID does not exist on object<Address>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
138
            $address->write();
139
            $member->DefaultBillingAddressID = $order->BillingAddressID;
140
        }
141 1
        if ($order->ShippingAddressID) {
142
            $address = $order->getShippingAddress();
143
            $address->MemberID = $member->ID;
0 ignored issues
show
Documentation introduced by
The property MemberID does not exist on object<Address>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
144
            $address->write();
145
            $member->DefaultShippingAddressID = $order->ShippingAddressID;
0 ignored issues
show
Bug introduced by
The property DefaultShippingAddressID does not seem to exist. Did you mean defaults?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
146
        }
147 1
        if ($member->isChanged()) {
148
            $member->write();
149
        }
150 1
    }
151
152
    public function setConfirmed($confirmed)
153
    {
154
        $this->confirmed = $confirmed;
155
156
        return $this;
157
    }
158
}
159