Passed
Pull Request — master (#99)
by Nic
02:48
created

AddToCartForm::getProductOptionSet()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 46
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 27
c 0
b 0
f 0
nc 7
nop 0
dl 0
loc 46
rs 9.1768

1 Method

Rating   Name   Duplication   Size   Complexity  
A AddToCartForm::getProductVariations() 0 15 4
1
<?php
2
3
namespace Dynamic\Foxy\Form;
4
5
use Dynamic\Foxy\Extension\Shippable;
6
use Dynamic\Foxy\Model\FoxyHelper;
7
use Dynamic\Foxy\Model\OptionType;
8
use Dynamic\Foxy\Model\ProductOption;
9
use Dynamic\Foxy\Model\Variation;
10
use Dynamic\Foxy\Model\VariationType;
11
use Dynamic\Products\Page\Product;
0 ignored issues
show
Bug introduced by
The type Dynamic\Products\Page\Product 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...
12
use SilverStripe\CMS\Model\VirtualPage;
13
use SilverStripe\Forms\CompositeField;
14
use SilverStripe\Forms\DropdownField;
15
use SilverStripe\Forms\FieldList;
16
use SilverStripe\Forms\Form;
17
use SilverStripe\Forms\FormAction;
18
use SilverStripe\Forms\HeaderField;
19
use SilverStripe\Forms\HiddenField;
20
use SilverStripe\Forms\RequiredFields;
21
use SilverStripe\ORM\ArrayList;
22
use SilverStripe\ORM\DataList;
23
use SilverStripe\ORM\GroupedList;
24
use SilverStripe\ORM\HasManyList;
25
26
/**
27
 * Class AddToCartForm
28
 * @package Dynamic\Foxy\Form
29
 */
30
class AddToCartForm extends Form
31
{
32
    /**
33
     * @var
34
     */
35
    protected $helper;
36
37
    /**
38
     * @var
39
     */
40
    private $product;
41
42
    /**
43
     * @param $helper
44
     *
45
     * @return $this
46
     */
47
    public function setFoxyHelper($helper)
48
    {
49
        $helper = $helper === null ? FoxyHelper::create() : $helper;
50
        if ($helper instanceof FoxyHelper) {
51
            $this->helper = $helper;
52
53
            return $this;
54
        }
55
        throw new \InvalidArgumentException('$helper needs to be an instance of FoxyHelper.');
56
    }
57
58
    /**
59
     * @return FoxyHelper
60
     */
61
    public function getFoxyHelper()
62
    {
63
        if (!$this->helper) {
64
            $this->setFoxyHelper(FoxyHelper::create());
65
        }
66
67
        return $this->helper;
68
    }
69
70
    /**
71
     * @param $product
72
     *
73
     * @return $this
74
     */
75
    public function setProduct($product)
76
    {
77
        if ($product instanceof VirtualPage) {
78
            $product = $this->getFoxyHelper()->getProducts()->filter('ID', $product->CopyContentFromID)->first();
79
        }
80
81
        if ($product->isProduct()) {
82
            $this->product = $product;
83
84
            return $this;
85
        }
86
        throw new \InvalidArgumentException('$product needs to implement a Foxy DataExtension.');
87
    }
88
89
    /**
90
     * @return Product
91
     */
92
    public function getProduct()
93
    {
94
        return $this->product;
95
    }
96
97
    /**
98
     * AddToCartForm constructor.
99
     * @param $controller
100
     * @param $name
101
     * @param FieldList|null $fields
102
     * @param FieldList|null $actions
103
     * @param null $validator
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $validator is correct as it would always require null to be passed?
Loading history...
104
     * @param null $product
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $product is correct as it would always require null to be passed?
Loading history...
105
     * @param null $helper
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $helper is correct as it would always require null to be passed?
Loading history...
106
     * @throws \SilverStripe\ORM\ValidationException
107
     */
108
    public function __construct(
109
        $controller,
110
        $name,
111
        FieldList $fields = null,
112
        FieldList $actions = null,
113
        $validator = null,
114
        $product = null,
115
        $helper = null
116
    )
117
    {
118
        $this->setProduct($product);
119
        $this->setFoxyHelper($helper);
120
121
        $fields = ($fields != null && $fields->exists()) ?
122
            $this->getProductFields($fields) :
123
            $this->getProductFields(FieldList::create());
124
125
        $actions = ($actions != null && $actions->exists()) ?
126
            $this->getProductActions($actions) :
127
            $this->getProductActions(FieldList::create());
128
129
        $validator = (!empty($validator) || $validator != null) ? $validator : RequiredFields::create();
130
131
        parent::__construct($controller, $name, $fields, $actions, $validator);
132
133
        //have to call after parent::__construct()
134
        $this->setAttribute('action', FoxyHelper::FormActionURL());
135
        $this->disableSecurityToken();
136
        $this->setHTMLID($this->getTemplateHelper()->generateFormID($this) . "_{$product->ID}");
137
    }
138
139
    /**
140
     * @param FieldList $fields
141
     *
142
     * @return FieldList
143
     */
144
    protected function getProductFields(FieldList $fields)
145
    {
146
        $hiddenTitle = ($this->product->ReceiptTitle) ?
147
            htmlspecialchars($this->product->ReceiptTitle) :
148
            htmlspecialchars($this->product->Title);
149
        $code = $this->product->Code;
150
151
        if ($this->product->isAvailable()) {
152
            $fields->push(
153
                HiddenField::create('name')
154
                    ->setValue(
155
                        self::getGeneratedValue($code, 'name', $hiddenTitle, 'value')
156
                    )
157
            );
158
159
            $fields->push(
160
                HiddenField::create('category')
161
                    ->setValue(
162
                        self::getGeneratedValue($code, 'category', $this->product->FoxyCategory()->Code, 'value')
163
                    )
164
            );
165
166
            $fields->push(
167
                HiddenField::create('code')
168
                    ->setValue(
169
                        self::getGeneratedValue($code, 'code', $this->product->Code, 'value')
170
                    )
171
            );
172
173
            $fields->push(
174
                HiddenField::create('product_id')
175
                    ->setValue(
176
                        self::getGeneratedValue($code, 'product_id', $this->product->ID, 'value')
177
                    )
178
                    ->setName('h:product_id')
179
            );
180
181
            $fields->push(
182
                HiddenField::create('price')
183
                    ->setValue(
184
                        self::getGeneratedValue($code, 'price', $this->product->Price, 'value')
185
                    )
186
            );
187
188
            if ($this->product->hasMethod('AbsoluteLink')) {
189
                $fields->push(
190
                    HiddenField::create('url')
191
                        ->setValue(
192
                            self::getGeneratedValue($code, 'url', $this->product->AbsoluteLink(), 'value')
193
                        )
194
                );
195
            }
196
197
            if ($this->product->hasExtension(Shippable::class)) {
198
                if ($this->product->Weight > 0) {
199
                    $fields->push(
200
                        HiddenField::create('weight')
201
                            ->setValue(
202
                                self::getGeneratedValue($code, 'weight', $this->product->Weight, 'value')
203
                            )
204
                    );
205
                }
206
            }
207
208
            $image = null;
209
            if ($this->product->hasMethod('getImage')) {
210
                if ($this->product->getImage()) {
211
                    $image = $this->product->getImage()->CMSThumbnail()->absoluteURL;
212
                }
213
                if ($image) {
214
                    $fields->push(
215
                        HiddenField::create('image')
216
                            ->setValue(
217
                                self::getGeneratedValue($code, 'image', $image, 'value')
218
                            )
219
                    );
220
                }
221
            }
222
223
            if ($this->product->QuantityMax > 0) {
224
                $fields->push(
225
                    HiddenField::create('quantity_max')
226
                        ->setValue(self::getGeneratedValue($code, 'quantity_max', $this->product->QuantityMax, 'value'))
227
                );
228
            }
229
230
            $fields->push($this->getProductVariations());
231
232
233
            if ($this->product->QuantityMax != 1) {
234
                $fields->push(QuantityField::create('x:visibleQuantity')->setTitle('Quantity')->setValue(1));
235
            }
236
            $fields->push(
237
                HiddenField::create('quantity')
238
                    ->setValue(
239
                        self::getGeneratedValue($code, 'quantity', 1, 'value')
240
                    )
241
            );
242
243
            $fields->push(
244
                HeaderField::create('submitPrice', '$' . $this->product->Price, 4)
245
                    ->addExtraClass('submit-price')
246
            );
247
        }
248
249
        $this->extend('updateProductFields', $fields);
250
251
        return $fields;
252
    }
253
254
    /**
255
     * @param FieldList $actions
256
     *
257
     * @return FieldList
258
     */
259
    protected function getProductActions(FieldList $actions)
260
    {
261
        if (!empty(trim($this->helper->getStoreCartURL())) && $this->product->isAvailable()) {
262
            $actions->push(
263
                FormAction::create(
264
                    'x:submit',
265
                    _t(__CLASS__ . '.AddToCart', 'Add to Cart')
266
                )
267
                    ->addExtraClass('fs-add-to-cart-button')
268
                    ->setName('x:submit')
269
            );
270
        }
271
272
        $this->extend('updateProductActions', $actions);
273
274
        return $actions;
275
    }
276
277
    /**
278
     * @param null $productCode
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $productCode is correct as it would always require null to be passed?
Loading history...
279
     * @param null $optionName
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $optionName is correct as it would always require null to be passed?
Loading history...
280
     * @param null $optionValue
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $optionValue is correct as it would always require null to be passed?
Loading history...
281
     * @param string $method
282
     * @param bool $output
283
     * @param bool $urlEncode
284
     *
285
     * @return null|string
286
     */
287
    // todo - Purchasable Extension or AddToCartForm? protected in Form
288
    public static function getGeneratedValue(
289
        $productCode = null,
290
        $optionName = null,
291
        $optionValue = null,
292
        $method = 'name',
293
        $output = false,
294
        $urlEncode = false
295
    )
296
    {
297
        $optionName = ($optionName !== null) ? preg_replace('/\s/', '_', $optionName) : $optionName;
0 ignored issues
show
introduced by
The condition $optionName !== null is always false.
Loading history...
298
        $helper = FoxyHelper::create();
299
300
        return $helper::fc_hash_value($productCode, $optionName, $optionValue, $method, $output, $urlEncode);
301
    }
302
303
    /**
304
     * @return CompositeField
305
     */
306
    protected function getProductVariations()
307
    {
308
        $types = VariationType::get();
309
310
        $variationsField = CompositeField::create();
311
312
        foreach ($types as $type) {
313
            if (($variations = $type->Variations()->filter('ProductID', $this->product->ID)) && $variations->count()) {
314
                $variationsField->push($this->createVariationField($type, $variations));
315
            }
316
        }
317
318
        $variationsField->addExtraClass('foxycartOptionsContainer');
319
320
        return $variationsField;
321
    }
322
323
    /**
324
     * @param VariationType $type
325
     * @param HasManyList $variations
326
     * @return DropdownField
327
     */
328
    protected function createVariationField(VariationType $type, HasManyList $variations)
329
    {
330
        $disabled = [];
331
        $list = [];
332
        $variationField = DropdownField::create(preg_replace('/\s/', '_', $type->Title));
333
334
        /** @var Variation $variation */
335
        foreach ($variations as $variation) {
336
            $name = self::getGeneratedValue(
337
                $this->product->Code,
338
                $type->Title,
339
                $variation->getGeneratedValue(),
340
                'value'
341
            );
342
343
            $list[$name] = $variation->getGeneratedTitle();
344
345
            if (!$variation->getAvailability()) {
346
                array_push($disabled, $name);
347
            }
348
        }
349
350
        $variationField->setSource($list)
351
            ->setTitle($type->Title)
352
            ->addExtraClass("product-options");
353
354
        if (!empty($disabled)) {
355
            $variationField->setDisabledItems($disabled);
356
        }
357
358
        return $variationField;
359
    }
360
}
361