1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Account page shows order history and a form to allow |
5
|
|
|
* the member to edit his/her details. |
6
|
|
|
* |
7
|
|
|
* @package shop |
8
|
|
|
*/ |
9
|
|
|
class AccountPage extends Page |
10
|
|
|
{ |
11
|
|
|
private static $icon = 'silvershop/images/icons/account'; |
12
|
|
|
|
13
|
1 |
|
public function canCreate($member = null, $context = array()) |
14
|
|
|
{ |
15
|
1 |
|
return !self::get()->exists(); |
16
|
|
|
} |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Returns the link or the URLSegment to the account page on this site |
20
|
|
|
* |
21
|
|
|
* @param boolean $urlSegment Return the URLSegment only |
22
|
|
|
* |
23
|
2 |
|
* @return mixed |
24
|
|
|
*/ |
25
|
2 |
|
public static function find_link($urlSegment = false) |
26
|
2 |
|
{ |
27
|
|
|
$page = self::get_if_account_page_exists(); |
28
|
|
|
return ($urlSegment) ? $page->URLSegment : $page->Link(); |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Return a link to view the order on the account page. |
33
|
|
|
* |
34
|
|
|
* @param int|string $orderID ID of the order |
35
|
1 |
|
* @param boolean $urlSegment Return the URLSegment only |
36
|
|
|
* |
37
|
1 |
|
* @return string |
38
|
1 |
|
*/ |
39
|
|
|
public static function get_order_link($orderID, $urlSegment = false) |
40
|
|
|
{ |
41
|
2 |
|
$page = self::get_if_account_page_exists(); |
42
|
|
|
return ($urlSegment ? $page->URLSegment . '/' : $page->Link()) . 'order/' . $orderID; |
43
|
2 |
|
} |
44
|
2 |
|
|
45
|
|
|
/** |
46
|
|
|
* @return AccountPage |
47
|
|
|
*/ |
48
|
|
|
protected static function get_if_account_page_exists() |
49
|
|
|
{ |
50
|
|
|
if ($page = DataObject::get_one('AccountPage')) { |
51
|
|
|
return $page; |
52
|
2 |
|
} |
53
|
|
|
user_error(_t('AccountPage.NO_PAGE', 'No AccountPage was found. Please create one in the CMS!'), E_USER_ERROR); |
54
|
|
|
return null; // just to keep static analysis happy |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* This module always requires a page model. |
59
|
|
|
*/ |
60
|
|
|
public function requireDefaultRecords() |
61
|
|
|
{ |
62
|
|
|
parent::requireDefaultRecords(); |
63
|
|
|
if (!self::get()->exists() && $this->config()->create_default_pages) { |
64
|
|
|
/** @var AccountPage $page */ |
65
|
|
|
$page = self::create( |
66
|
2 |
|
array( |
67
|
|
|
'Title' => 'Account', |
68
|
|
|
'URLSegment' => AccountPage_Controller::config()->url_segment, |
69
|
|
|
'ShowInMenus' => 0, |
70
|
|
|
) |
71
|
|
|
); |
72
|
|
|
$page->write(); |
73
|
|
|
$page->publish('Stage', 'Live'); |
74
|
|
|
$page->flushCache(); |
75
|
|
|
DB::alteration_message('Account page created', 'created'); |
76
|
|
|
} |
77
|
|
|
} |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
class AccountPage_Controller extends Page_Controller |
81
|
|
|
{ |
82
|
|
|
private static $url_segment = 'account'; |
83
|
|
|
|
84
|
|
|
private static $allowed_actions = array( |
85
|
|
|
'addressbook', |
86
|
|
|
'CreateAddressForm', |
87
|
4 |
|
'DefaultAddressForm', |
88
|
|
|
'editprofile', |
89
|
4 |
|
'EditAccountForm', |
90
|
4 |
|
'ChangePasswordForm', |
91
|
|
|
'changepassword', // redirects to editprofile |
92
|
4 |
|
'deleteaddress', |
93
|
4 |
|
'setdefaultbilling', |
94
|
|
|
'setdefaultshipping', |
95
|
|
|
); |
96
|
|
|
|
97
|
4 |
|
/** @var Member|ShopMember */ |
98
|
4 |
|
protected $member; |
99
|
4 |
|
|
100
|
|
|
public function init() |
101
|
|
|
{ |
102
|
4 |
|
parent::init(); |
103
|
4 |
|
if (!Member::currentUserID()) { |
104
|
4 |
|
$messages = array( |
105
|
4 |
|
'default' => _t( |
106
|
|
|
'AccountPage.LOGIN', |
107
|
3 |
|
'You\'ll need to login before you can access the account page. |
108
|
3 |
|
If you are not registered, you won\'t be able to access it until |
109
|
|
|
you make your first order, otherwise please enter your details below.' |
110
|
3 |
|
), |
111
|
|
|
'logInAgain' => _t( |
112
|
3 |
|
'AccountPage.LOGINAGAIN', |
113
|
3 |
|
'You have been logged out. If you would like to log in again, |
114
|
|
|
please do so below.' |
115
|
|
|
), |
116
|
|
|
); |
117
|
|
|
Security::permissionFailure($this, $messages); |
118
|
3 |
|
} else { |
119
|
|
|
$this->member = Member::currentUser(); |
|
|
|
|
120
|
3 |
|
} |
121
|
|
|
} |
122
|
|
|
|
123
|
2 |
|
public function getTitle() |
124
|
|
|
{ |
125
|
|
|
if ($this->dataRecord && $title = $this->dataRecord->Title) { |
126
|
2 |
|
return $title; |
127
|
2 |
|
} |
128
|
2 |
|
return _t('AccountPage.Title', "Account"); |
129
|
|
|
} |
130
|
|
|
|
131
|
2 |
|
public function getMember() |
132
|
|
|
{ |
133
|
2 |
|
return $this->member; |
134
|
2 |
|
} |
135
|
2 |
|
|
136
|
2 |
|
public function addressbook() |
137
|
2 |
|
{ |
138
|
2 |
|
return array( |
139
|
2 |
|
'DefaultAddressForm' => $this->DefaultAddressForm(), |
140
|
2 |
|
'CreateAddressForm' => $this->CreateAddressForm(), |
141
|
2 |
|
); |
142
|
2 |
|
} |
143
|
2 |
|
|
144
|
2 |
|
public function DefaultAddressForm() |
145
|
2 |
|
{ |
146
|
2 |
|
$addresses = $this->member->AddressBook()->sort('Created', 'DESC'); |
147
|
2 |
|
if ($addresses->exists()) { |
148
|
2 |
|
$fields = FieldList::create( |
149
|
2 |
|
DropdownField::create( |
150
|
2 |
|
"DefaultShippingAddressID", |
151
|
2 |
|
_t("Address.ShippingAddress", "Shipping Address"), |
152
|
|
|
$addresses->map('ID', 'toString')->toArray() |
153
|
2 |
|
), |
154
|
|
|
DropdownField::create( |
155
|
|
|
"DefaultBillingAddressID", |
156
|
2 |
|
_t("Address.BillingAddress", "Billing Address"), |
157
|
|
|
$addresses->map('ID', 'toString')->toArray() |
158
|
|
|
) |
159
|
|
|
); |
160
|
|
|
$actions = FieldList::create( |
161
|
|
|
FormAction::create("savedefaultaddresses", _t("Address.SaveDefaults", "Save Defaults")) |
162
|
|
|
); |
163
|
|
|
$form = Form::create($this, "DefaultAddressForm", $fields, $actions); |
164
|
|
|
$form->loadDataFrom($this->member); |
165
|
|
|
|
166
|
|
|
return $form; |
167
|
|
|
} |
168
|
|
|
|
169
|
2 |
|
return false; |
170
|
|
|
} |
171
|
2 |
|
|
172
|
2 |
|
public function savedefaultaddresses($data, $form) |
173
|
2 |
|
{ |
174
|
2 |
|
$form->saveInto($this->member); |
175
|
2 |
|
$this->member->write(); |
|
|
|
|
176
|
2 |
|
|
177
|
2 |
|
$this->extend('updateDefaultAddressFormResponse', $form, $data, $response); |
|
|
|
|
178
|
2 |
|
|
179
|
2 |
|
return $response ?: $this->redirect($this->Link('addressbook')); |
180
|
|
|
} |
181
|
|
|
|
182
|
2 |
|
public function CreateAddressForm() |
183
|
|
|
{ |
184
|
2 |
|
$singletonaddress = singleton('Address'); |
185
|
2 |
|
$fields = $singletonaddress->getFrontEndFields(); |
186
|
2 |
|
$actions = FieldList::create( |
187
|
2 |
|
FormAction::create("saveaddress", _t("Address.SaveNew", "Save New Address")) |
188
|
|
|
); |
189
|
|
|
$validator = RequiredFields::create($singletonaddress->getRequiredFields()); |
190
|
2 |
|
$form = Form::create($this, "CreateAddressForm", $fields, $actions, $validator); |
191
|
1 |
|
$this->extend('updateCreateAddressForm', $form); |
192
|
1 |
|
return $form; |
193
|
|
|
} |
194
|
2 |
|
|
195
|
|
|
public function saveaddress($data, $form) |
196
|
2 |
|
{ |
197
|
|
|
$member = $this->getMember(); |
198
|
|
|
$address = Address::create(); |
199
|
|
|
$form->saveInto($address); |
200
|
2 |
|
$address->MemberID = $member->ID; |
201
|
|
|
|
202
|
|
|
// Add value for Country if missing (due readonly field in form) |
203
|
|
|
if ($country = SiteConfig::current_site_config()->getSingleCountry()) { |
204
|
2 |
|
$address->Country = $country; |
205
|
|
|
} |
206
|
2 |
|
|
207
|
|
|
$address->write(); |
208
|
2 |
|
|
209
|
|
|
if (!$member->DefaultShippingAddressID) { |
210
|
|
|
$member->DefaultShippingAddressID = $address->ID; |
211
|
|
|
$member->write(); |
|
|
|
|
212
|
|
|
} |
213
|
|
|
if (!$member->DefaultBillingAddressID) { |
214
|
|
|
$member->DefaultBillingAddressID = $address->ID; |
215
|
|
|
$member->write(); |
216
|
|
|
} |
217
|
|
|
$form->sessionMessage(_t("CreateAddressForm.SAVED", "Your address has been saved"), "good"); |
218
|
|
|
|
219
|
|
|
$this->extend('updateCreateAddressFormResponse', $form, $data, $response); |
|
|
|
|
220
|
|
|
|
221
|
|
|
return $response ?: $this->redirect($this->Link('addressbook')); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
public function editprofile() |
225
|
|
|
{ |
226
|
|
|
return array(); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* @param SS_HTTPRequest $req |
231
|
|
|
* @return SS_HTTPResponse |
232
|
|
|
*/ |
233
|
|
|
function deleteaddress($req) |
|
|
|
|
234
|
|
|
{ |
235
|
|
|
// NOTE: we don't want to fully delete the address because it's presumably still |
236
|
|
|
// attached to an order. Setting MemberID to 0 means it won't show up in the address |
237
|
|
|
// book any longer. |
238
|
|
|
$address = $this->member->AddressBook()->byID($req->param('ID')); |
239
|
|
|
if ($address) { |
240
|
|
|
$address->MemberID = 0; |
241
|
|
|
$address->write(); |
242
|
|
|
} else { |
243
|
|
|
$this->httpError(404, 'Address not found'); |
244
|
|
|
} |
245
|
|
|
return $this->redirectBack(); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* @param SS_HTTPRequest $req |
250
|
|
|
* @return SS_HTTPResponse |
251
|
|
|
*/ |
252
|
2 |
|
function setdefaultbilling($req) |
|
|
|
|
253
|
|
|
{ |
254
|
|
|
$this->member->DefaultBillingAddressID = $req->param('ID'); |
255
|
|
|
$this->member->write(); |
|
|
|
|
256
|
|
|
return $this->redirectBack(); |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* @param SS_HTTPRequest $req |
261
|
|
|
* @return SS_HTTPResponse |
262
|
|
|
*/ |
263
|
|
|
function setdefaultshipping($req) |
|
|
|
|
264
|
|
|
{ |
265
|
|
|
$this->member->DefaultShippingAddressID = $req->param('ID'); |
266
|
|
|
$this->member->write(); |
|
|
|
|
267
|
|
|
return $this->redirectBack(); |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* Return a form allowing the user to edit their details. |
272
|
|
|
* |
273
|
|
|
* @return ShopAccountForm |
274
|
|
|
*/ |
275
|
|
|
public function EditAccountForm() |
276
|
|
|
{ |
277
|
|
|
return ShopAccountForm::create($this, 'EditAccountForm'); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
public function ChangePasswordForm() |
281
|
|
|
{ |
282
|
|
|
$form = ChangePasswordForm::create($this, "ChangePasswordForm"); |
283
|
|
|
$this->extend('updateChangePasswordForm', $form); |
284
|
|
|
$this->data()->extend('updateChangePasswordForm', $form); |
285
|
|
|
|
286
|
|
|
if ($this->data()->hasMethod('updateChangePasswordForm')) { // if accessing through the model |
287
|
|
|
Deprecation::notice( |
288
|
|
|
'2.0', |
289
|
|
|
'Please access updateChangePasswordForm through AccountPage_Controller instead of AccountPage (this extension point is due to be removed)' |
290
|
|
|
); |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
return $form; |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
/** |
297
|
|
|
* By default, ChangePasswordForm redirects to /account/changepassword when it's done. |
298
|
|
|
* This catches that and sends it back to editprofile, which seems easier and less error-prone |
299
|
|
|
* than the alternative of trying to manipulate the BackURL field. |
300
|
|
|
*/ |
301
|
|
|
public function changepassword() |
302
|
|
|
{ |
303
|
|
|
$this->redirect($this->Link('editprofile')); |
304
|
|
|
} |
305
|
|
|
} |
306
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.