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

CheckoutComponentConfig   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 72.81%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
wmc 39
c 3
b 1
f 0
lcom 1
cbo 7
dl 0
loc 207
ccs 83
cts 114
cp 0.7281
rs 8.2857

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getOrder() 0 4 1
A getComponents() 0 7 2
A getFormFields() 0 12 3
A getRequiredFields() 0 8 2
C validateData() 0 28 7
A getData() 0 15 3
A setData() 0 6 2
B dependantData() 0 24 6
C addComponent() 0 24 7
B getComponentByType() 0 14 5
1
<?php
2
3
use SilverStripe\Omnipay\GatewayInfo;
4
5
/**
6
 * @package shop
7
 */
8
class CheckoutComponentConfig extends Object
9
{
10
    protected $components;
11
12
    protected $order;
13
14
    protected $namespaced; //namespace fields according to their component
15
16 12
    public function __construct(Order $order, $namespaced = true)
17
    {
18 12
        $this->components = ArrayList::create();
19 12
        $this->order = $order;
20 12
        $this->namespaced = $namespaced;
21 12
    }
22
23 4
    public function getOrder()
24
    {
25 4
        return $this->order;
26
    }
27
28
    /**
29
     * @param CheckoutComponent $component
30
     * @param string            $insertBefore The class of the component to insert this one before
31
     */
32 12
    public function addComponent(CheckoutComponent $component, $insertBefore = null)
33
    {
34 12
        if ($this->namespaced) {
35 8
            $component = new CheckoutComponent_Namespaced($component);
36 8
        }
37 12
        if ($insertBefore) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertBefore of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
38
            $existingItems = $this->getComponents();
39
            $this->components = new ArrayList;
40
            $inserted = false;
41
            foreach ($existingItems as $existingItem) {
42 1
                if (!$inserted && $existingItem instanceof $insertBefore) {
43 1
                    $this->components->push($component);
44
                    $inserted = true;
45
                }
46
                $this->components->push($existingItem);
47
            }
48
            if (!$inserted) {
49
                $this->components->push($component);
50
            }
51
        } else {
52 12
            $this->getComponents()->push($component);
53
        }
54 12
        return $this;
55
    }
56
57
    /**
58
     * @return ArrayList Of GridFieldComponent
59
     */
60 12
    public function getComponents()
61
    {
62 12
        if (!$this->components) {
63
            $this->components = ArrayList::create();
64
        }
65 12
        return $this->components;
66
    }
67
68
    /**
69
     * Returns the first available component with the given class or interface.
70
     *
71
     * @param String ClassName
72
     *
73
     * @return GridFieldComponent
74
     */
75 2
    public function getComponentByType($type)
76
    {
77 2
        foreach ($this->components as $component) {
78 2
            if ($this->namespaced) {
79 1
                if ($component->Proxy() instanceof $type) {
80 2
                    return $component->Proxy();
81
                }
82 1
            } else {
83 1
                if ($component instanceof $type) {
84
                    return $component;
85 2
                }
86
            }
87 2
        }
88 1
    }
89
90
    /**
91
     * Get combined form fields
92
     *
93
     * @return FieldList namespaced fields
94
     */
95 6
    public function getFormFields()
96
    {
97 6
        $fields = FieldList::create();
98 6
        foreach ($this->getComponents() as $component) {
99 6
            if ($cfields = $component->getFormFields($this->order)) {
100 6
                $fields->merge($cfields);
101 6
            } else {
102
                user_error("getFields on  " . get_class($component) . " must return a FieldList");
103
            }
104 6
        }
105 6
        return $fields;
106
    }
107
108 6
    public function getRequiredFields()
109
    {
110 6
        $required = array();
111 6
        foreach ($this->getComponents() as $component) {
112 6
            $required = array_merge($required, $component->getRequiredFields($this->order));
113 6
        }
114 6
        return $required;
115
    }
116
117
    /**
118
     * Validate every component against given data.
119
     *
120
     * @param  array $data data to validate
121
     *
122
     * @return boolean validation result
123
     * @throws ValidationException
124
     */
125 10
    public function validateData($data)
126
    {
127 10
        $result = ValidationResult::create();
128 10
        foreach ($this->getComponents() as $component) {
129
            try {
130 10
                $component->validateData($this->order, $this->dependantData($component, $data));
131 10
            } catch (ValidationException $e) {
132
                //transfer messages into a single result
133 3
                foreach ($e->getResult()->messageList() as $code => $message) {
134 3
                    if (is_numeric($code)) {
135 1
                        $code = null;
136
                    }
137 3
                    if ($this->namespaced) {
138 3
                        $code = $component->namespaceFieldName($code);
139 3
                    }
140 3
                    $result->error($message, $code);
141 4
                }
142
            }
143 10
        }
144
145 10
        $this->order->extend('onValidateDataOnCheckout', $result);
146
147 10
        if (!$result->valid()) {
148 3
            throw new ValidationException($result);
149
        }
150
151 7
        return true;
152
    }
153
154
    /**
155
     * Get combined data
156
     *
157
     * @return array map of field names to data values
158
     */
159 6
    public function getData()
160
    {
161 6
        $data = array();
162
163 6
        foreach ($this->getComponents() as $component) {
164 6
            $orderdata = $component->getData($this->order);
165
166 6
            if (is_array($orderdata)) {
167 6
                $data = array_merge($data, $orderdata);
168 6
            } else {
169
                user_error("getData on  " . $component->name() . " must return an array");
170
            }
171 6
        }
172 6
        return $data;
173
    }
174
175
    /**
176
     * Set data on all components
177
     *
178
     * @param array $data map of field names to data values
179
     */
180 6
    public function setData($data)
181
    {
182 6
        foreach ($this->getComponents() as $component) {
183 6
            $component->setData($this->order, $this->dependantData($component, $data));
184 6
        }
185 6
    }
186
187
    /**
188
     * Helper function for saving data from other components.
189
     */
190 11
    protected function dependantData($component, $data)
191
    {
192 11
        if (!$this->namespaced) { //no need to try and get un-namespaced dependant data
193 3
            return $data;
194 6
        }
195 8
        $dependantdata = array();
196 8
        foreach ($component->dependsOn() as $dependanttype) {
197
            $dependant = null;
198
            foreach ($this->components as $check) {
199
                if (get_class($check->Proxy()) == $dependanttype) {
200
                    $dependant = $check;
201
                    break;
202
                }
203
            }
204
            if (!$dependant) {
205
                user_error("Could not find a $dependanttype component, as depended by " . $component->name());
206
            }
207
            $dependantdata = array_merge(
208
                $dependantdata,
209
                $component->namespaceData($dependant->unnamespaceData($data))
210
            );
211 8
        }
212 8
        return array_merge($dependantdata, $data);
213
    }
214
}
215
216
class SinglePageCheckoutComponentConfig extends CheckoutComponentConfig
217
{
218 2
    public function __construct(Order $order)
219
    {
220 2
        parent::__construct($order);
221 2
        $this->addComponent(CustomerDetailsCheckoutComponent::create());
222 2
        $this->addComponent(ShippingAddressCheckoutComponent::create());
223 2
        $this->addComponent(BillingAddressCheckoutComponent::create());
224 2
        if (Checkout::member_creation_enabled() && !Member::currentUserID()) {
225
            $this->addComponent(MembershipCheckoutComponent::create());
226
        }
227 2
        if (count(GatewayInfo::getSupportedGateways()) > 1) {
228 2
            $this->addComponent(PaymentCheckoutComponent::create());
229 2
        }
230 2
        $this->addComponent(NotesCheckoutComponent::create());
231 2
        $this->addComponent(TermsCheckoutComponent::create());
232 2
    }
233
}
234