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

src/Checkout/CheckoutComponentConfig.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace SilverShop\Checkout;
4
5
use SilverShop\Checkout\Component\CheckoutComponent;
6
use SilverShop\Checkout\Component\CheckoutComponentNamespaced;
7
use SilverShop\Model\Order;
8
use SilverStripe\Core\Injector\Injectable;
9
use SilverStripe\Forms\FieldList;
10
use SilverStripe\ORM\ArrayList;
11
use SilverStripe\ORM\ValidationException;
12
use SilverStripe\ORM\ValidationResult;
13
14
/**
15
 * @package shop
16
 */
17
class CheckoutComponentConfig
18
{
19
    use Injectable;
20
21
    protected $components;
22
23
    protected $order;
24
25
    protected $namespaced; //namespace fields according to their component
26
27
    public function __construct(Order $order, $namespaced = true)
28
    {
29
        $this->components = ArrayList::create();
30
        $this->order = $order;
31
        $this->namespaced = $namespaced;
32
    }
33
34
    public function getOrder()
35
    {
36
        return $this->order;
37
    }
38
39
    /**
40
     * @param CheckoutComponent $component
41
     * @param string            $insertBefore The class of the component to insert this one before
42
     * @return $this
43
     */
44
    public function addComponent(CheckoutComponent $component, $insertBefore = null)
45
    {
46
        if ($this->namespaced) {
47
            $component = CheckoutComponentNamespaced::create($component);
48
        }
49
        if ($insertBefore) {
50
            $existingItems = $this->getComponents();
51
            $this->components = ArrayList::create();
52
            $inserted = false;
53
            foreach ($existingItems as $existingItem) {
54
                if (!$inserted && $existingItem instanceof $insertBefore) {
55
                    $this->components->push($component);
56
                    $inserted = true;
57
                }
58
                $this->components->push($existingItem);
59
            }
60
            if (!$inserted) {
61
                $this->components->push($component);
62
            }
63
        } else {
64
            $this->getComponents()->push($component);
65
        }
66
        return $this;
67
    }
68
69
    /**
70
     * @return ArrayList Of CheckoutComponent
71
     */
72
    public function getComponents()
73
    {
74
        if (!$this->components) {
75
            $this->components = ArrayList::create();
76
        }
77
        return $this->components;
78
    }
79
80
    /**
81
     * Returns the first available component with the given class or interface.
82
     *
83
     * @param String ClassName
0 ignored issues
show
The type SilverShop\Checkout\ClassName was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
84
     *
85
     * @return CheckoutComponent
86
     */
87
    public function getComponentByType($type)
88
    {
89
        foreach ($this->components as $component) {
90
            if ($this->namespaced) {
91
                if ($component->Proxy() instanceof $type) {
92
                    return $component->Proxy();
93
                }
94
            } else {
95
                if ($component instanceof $type) {
96
                    return $component;
97
                }
98
            }
99
        }
100
    }
101
102
    /**
103
     * Whether or not this config has a component that collects payment data.
104
     * Should be used to determine whether or not to add an additional payment step after checkout.
105
     * @return bool
106
     */
107
    public function hasComponentWithPaymentData()
108
    {
109
        foreach ($this->getComponents() as $component) {
110
            if ($component->providesPaymentData()) {
111
                return true;
112
            }
113
        }
114
115
        return false;
116
    }
117
118
    /**
119
     * Get combined form fields
120
     *
121
     * @return FieldList namespaced fields
122
     */
123
    public function getFormFields()
124
    {
125
        $fields = FieldList::create();
126
        foreach ($this->getComponents() as $component) {
127
            if ($cfields = $component->getFormFields($this->order)) {
128
                $fields->merge($cfields);
129
            } else {
130
                user_error('getFields on  ' . get_class($component) . ' must return a FieldList');
131
            }
132
        }
133
        return $fields;
134
    }
135
136
    public function getRequiredFields()
137
    {
138
        $required = array();
139
        foreach ($this->getComponents() as $component) {
140
            $required = array_merge($required, $component->getRequiredFields($this->order));
141
        }
142
        return $required;
143
    }
144
145
    /**
146
     * Validate every component against given data.
147
     *
148
     * @param array $data data to validate
149
     *
150
     * @return boolean validation result
151
     * @throws ValidationException
152
     */
153
    public function validateData($data)
154
    {
155
        $result = ValidationResult::create();
156
        foreach ($this->getComponents() as $component) {
157
            try {
158
                $component->validateData($this->order, $this->dependantData($component, $data));
159
            } catch (ValidationException $e) {
160
                //transfer messages into a single result
161
                foreach ($e->getResult()->getMessages() as $code => $message) {
162
                    if (is_numeric($code)) {
163
                        $code = null;
164
                    }
165
                    if ($this->namespaced) {
166
                        $code = $component->namespaceFieldName($code);
167
                    }
168
                    $result->addError($message['message'], $code);
169
                }
170
            }
171
        }
172
173
        $this->order->extend('onValidateDataOnCheckout', $result);
174
175
        if (!$result->isValid()) {
176
            throw new ValidationException($result);
177
        }
178
179
        return true;
180
    }
181
182
    /**
183
     * Get combined data
184
     *
185
     * @return array map of field names to data values
186
     */
187
    public function getData()
188
    {
189
        $data = array();
190
191
        foreach ($this->getComponents() as $component) {
192
            $orderdata = $component->getData($this->order);
193
194
            if (is_array($orderdata)) {
195
                $data = array_merge($data, $orderdata);
196
            } else {
197
                user_error('getData on  ' . $component->name() . ' must return an array');
198
            }
199
        }
200
        return $data;
201
    }
202
203
    /**
204
     * Set data on all components
205
     *
206
     * @param array $data map of field names to data values
207
     */
208
    public function setData($data)
209
    {
210
        foreach ($this->getComponents() as $component) {
211
            $component->setData($this->order, $this->dependantData($component, $data));
212
        }
213
    }
214
215
    /**
216
     * Helper function for saving data from other components.
217
     */
218
    protected function dependantData($component, $data)
219
    {
220
        if (!$this->namespaced) { //no need to try and get un-namespaced dependant data
221
            return $data;
222
        }
223
        $dependantdata = array();
224
        foreach ($component->dependsOn() as $dependanttype) {
225
            $dependant = null;
226
            foreach ($this->components as $check) {
227
                if (get_class($check->Proxy()) == $dependanttype) {
228
                    $dependant = $check;
229
                    break;
230
                }
231
            }
232
            if (!$dependant) {
233
                user_error("Could not find a $dependanttype component, as depended by " . $component->name());
234
            }
235
            $dependantdata = array_merge(
236
                $dependantdata,
237
                $component->namespaceData($dependant->unnamespaceData($data))
238
            );
239
        }
240
        return array_merge($dependantdata, $data);
241
    }
242
}
243