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

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

Severity
1
<?php
2
3
namespace SilverShop\Checkout\Component;
4
5
use SilverShop\Model\Order;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\Forms\CompositeField;
8
use SilverStripe\Forms\DropdownField;
9
use SilverStripe\Forms\FieldList;
10
use SilverStripe\Forms\OptionsetField;
11
use SilverStripe\i18n\i18nEntityProvider;
12
use SilverStripe\ORM\ValidationException;
13
use SilverStripe\ORM\ValidationResult;
14
use SilverStripe\Security\Security;
15
use SilverStripe\View\Requirements;
16
17
/**
18
 * Adds the ability to use the member's address book for choosing addresses
19
 */
20
abstract class AddressBook extends Address implements i18nEntityProvider
21
{
22
    /**
23
     * The composite field tag to use
24
     *
25
     * @config
26
     * @var    string
27
     */
28
    private static $composite_field_tag = 'div';
29
30
    protected $addtoaddressbook = true;
31
32
    public function getFormFields(Order $order)
33
    {
34
        $fields = parent::getFormFields($order);
35
36
        if ($existingaddressfields = $this->getExistingAddressFields()) {
37
            Requirements::javascript('silverstripe/admin:thirdparty/jquery/jquery.js');
38
            Requirements::javascript('silvershop/core:client/dist/javascript/CheckoutPage.js');
39
            
40
            // add the fields for a new address after the dropdown field
41
            $existingaddressfields->merge($fields);
42
            // group under a composite field (invisible by default) so we
43
            // easily know which fields to show/hide
44
            $label = _t(
45
                "SilverShop\Model\Address.{$this->addresstype}Address",
46
                "{$this->addresstype} Address"
47
            );
48
49
            return FieldList::create(
50
                CompositeField::create($existingaddressfields)
51
                    ->addExtraClass('hasExistingValues')
52
                    ->setLegend($label)
53
                    ->setTag(Config::inst()->get(self::class, 'composite_field_tag'))
54
            );
55
        }
56
57
        return $fields;
58
    }
59
60
    /**
61
     * Allow choosing from an existing address
62
     *
63
     * @return FieldList|null fields for
64
     */
65
    public function getExistingAddressFields()
66
    {
67
        $member = Security::getCurrentUser();
68
        if ($member && $member->AddressBook()->exists()) {
69
            $addressoptions = $member->AddressBook()->sort('Created', 'DESC')->map('ID', 'toString')->toArray();
70
            $addressoptions['newaddress'] = _t('SilverShop\Model\Address.CreateNewAddress', 'Create new address');
71
            $fieldtype = count($addressoptions) > 3 ? DropdownField::class : OptionsetField::class;
72
73
            $label = _t("SilverShop\Model\Address.Existing{$this->addresstype}Address", "Existing {$this->addresstype} Address");
74
75
            return FieldList::create(
76
                $fieldtype::create(
77
                    $this->addresstype . 'AddressID',
78
                    $label,
79
                    $addressoptions,
80
                    $member->{'Default' . $this->addresstype . 'AddressID'}
81
                )->addExtraClass('existingValues')
82
            );
83
        }
84
85
        return null;
86
    }
87
88
    /**
89
     * We don't know at the front end which fields are required so we defer to validateData
90
     *
91
     * @param Order $order
92
     *
93
     * @return array
94
     */
95
    public function getRequiredFields(Order $order)
96
    {
97
        return [];
98
    }
99
100
    /**
101
     * @param Order $order
102
     * @param array $data
103
     *
104
     * @throws ValidationException
105
     */
106
    public function validateData(Order $order, array $data)
107
    {
108
        $result = ValidationResult::create();
109
        $existingID =
110
            !empty($data[$this->addresstype . 'AddressID']) ? (int)$data[$this->addresstype . 'AddressID'] : 0;
111
112
        if ($existingID) {
113
            $member = Security::getCurrentUser();
114
            // If existing address selected, check that it exists in $member->AddressBook
115
            if (!$member || !$member->AddressBook()->byID($existingID)) {
0 ignored issues
show
$member is of type SilverStripe\Security\Member, thus it always evaluated to true.
Loading history...
116
                $result->addError('Invalid address supplied', $this->addresstype . 'AddressID');
117
                throw new ValidationException($result);
118
            }
119
        } else {
120
            // Otherwise, require the normal address fields
121
            $required = parent::getRequiredFields($order);
122
            $addressLabels = singleton(\SilverShop\Model\Address::class)->fieldLabels(false);
123
124
            foreach ($required as $fieldName) {
125
                if (empty($data[$fieldName])) {
126
                    // attempt to get the translated field name
127
                    $fieldLabel = isset($addressLabels[$fieldName]) ? $addressLabels[$fieldName] : $fieldName;
128
                    $errorMessage = _t(
129
                        'SilverShop\Forms.FIELDISREQUIRED',
130
                        '{name} is required',
131
                        array('name' => $fieldLabel)
132
                    );
133
134
                    $result->addError($errorMessage, $fieldName);
135
                    throw new ValidationException($result);
136
                }
137
            }
138
        }
139
    }
140
141
    /**
142
     * Create a new address if the existing address has changed, or is not yet
143
     * created.
144
     *
145
     * @param  Order $order order to get addresses from
146
     * @param  array $data  data to set
147
     * @throws ValidationException
148
     */
149
    public function setData(Order $order, array $data)
150
    {
151
        $existingID =
152
            !empty($data[$this->addresstype . 'AddressID']) ? (int)$data[$this->addresstype . 'AddressID'] : 0;
153
        if ($existingID > 0) {
154
            $order->{$this->addresstype . 'AddressID'} = $existingID;
155
            $order->write();
156
            $order->extend('onSet' . $this->addresstype . 'Address', $address);
157
        } else {
158
            parent::setData($order, $data);
159
        }
160
    }
161
162
    /**
163
     * Provide translatable entities for this class
164
     *
165
     * @return array
166
     */
167
    public function provideI18nEntities()
168
    {
169
        if ($this->addresstype) {
170
            return [
171
172
                "SilverShop\Model\Address.{$this->addresstype}Address" => [
173
                    "{$this->addresstype} Address",
174
                    "Label for the {$this->addresstype} address",
175
                ],
176
                "SilverShop\Model\Address.Existing{$this->addresstype}Address" => [
177
                    "Existing {$this->addresstype} Address",
178
                    "Label to select an existing {$this->addresstype} Address",
179
                ],
180
            ];
181
        }
182
183
        return array();
184
    }
185
}
186