Completed
Pull Request — master (#10)
by Franco
01:59
created

requireDefaultRecords()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 25
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 18
nc 2
nop 0
1
<?php
2
/**
3
 * @property Text $ThanksMessage
4
 * @property Int  $CartEmailRecipientID
5
 *
6
 * @method Member CartEmailRecipient
7
 */
8
class DMSDocumentCartCheckoutPage extends Page
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
9
{
10
    private static $db = array(
0 ignored issues
show
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
11
        'ThanksMessage' => 'Text',
12
    );
13
14
    private static $has_one = array(
0 ignored issues
show
Unused Code introduced by
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
15
        'CartEmailRecipient'     => 'Member'
16
    );
17
18
    private static $defaults = array(
0 ignored issues
show
Unused Code introduced by
The property $defaults is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
19
        'URLSegment'  => 'checkout',
20
        'ShowInMenus' => false,
21
    );
22
23
    public function getCMSFields()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
24
    {
25
        $fields = parent::getCMSFields();
26
        $members = Member::get('Member');
27
        $recipientDropDown = DropdownField::create(
28
            'CartEmailRecipientID',
29
            _t('DMSDocumentCartCheckoutPage.CART_RECIPIENT', 'Account to receive document print requests'),
30
            $members->Map()->toArray()
31
        )->setEmptyString(_t(
32
            'DMSDocumentCartCheckoutPage.CART_RECIPIENT_EMPTY_STRING',
33
            'Select a member'
34
        ));
35
        $fields->insertBefore('Content', $recipientDropDown);
36
37
        $fields->insertBefore(
38
            'Content',
39
            TextareaField::create(
40
                'ThanksMessage',
41
                _t('DMSDocumentCartCheckoutPage.THANK_YOU_MESSAGE', 'Thank you message')
42
            )
43
        );
44
45
        return $fields;
46
    }
47
    /**
48
     * Automatically create a CheckoutPage if one is not found
49
     * on the site at the time the database is built (dev/build).
50
     */
51
    function requireDefaultRecords()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
52
    {
53
        parent::requireDefaultRecords();
54
55
        if (!SiteTree::get_one($this->class)) {
56
            /** @var DMSDocumentCartCheckoutPage $page */
57
            $page = self::create();
58
            $page->Title = 'Request a printed copy';
59
            $page->MenuTitle = 'Document Cart Checkout';
60
            $page->Content = '';
61
            $page->URLSegment = 'checkout';
62
            $page->ShowInMenus = 0;
63
            $page->ThanksMessage = 'Thanks for your request.';
64
            $page->write();
65
            $page->publish('Stage', 'Live');
66
            $page->flushCache();
67
            DB::alteration_message(
68
                _t(
69
                    'DMSDocumentCartCheckoutPage.ALTERATION_MESSAGE',
70
                    'Document Cart Checkout page \'Request a printed copy\' created'
71
                ),
72
                'created'
73
            );
74
        }
75
    }
76
}
77
78
class DMSDocumentCartCheckoutPage_Controller extends Page_Controller
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
79
{
80
    private static $allowed_actions = array(
0 ignored issues
show
Unused Code introduced by
The property $allowed_actions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
81
        'DMSDocumentRequestForm'
82
    );
83
84
    /**
85
     * An array containing the recipients basic information
86
     *
87
     * @var array
88
     */
89
    public static $receiverInfo = array(
90
        'ReceiverName'            => '',
91
        'ReceiverPhone'           => '',
92
        'ReceiverEmail'           => '',
93
        'DeliveryAddressLine1'    => '',
94
        'DeliveryAddressLine2'    => '',
95
        'DeliveryAddressCountry'  => '',
96
        'DeliveryAddressPostCode' => '',
97
    );
98
99
    /**
100
     * Gets and displays an editable list of items within the cart, as well as a contact form with entry
101
     * fields for the recipients information.
102
     *
103
     * To extend use the following from within an Extension subclass:
104
     *
105
     * <code>
106
     * public function updateDMSDocumentRequestForm($form)
107
     * {
108
     *     // Do something here
109
     * }
110
     * </code>
111
     *
112
     * @return DMSDocumentRequestForm
113
     */
114
    public function DMSDocumentRequestForm()
115
    {
116
        $fields = DMSDocumentCartSubmission::create()->scaffoldFormFields();
117
        $fields->replaceField('DeliveryAddressLine2', TextField::create('DeliveryAddressLine2', ''));
118
        $fields->replaceField(
119
            'DeliveryAddressCountry',
120
            CountryDropdownField::create(
121
                'DeliveryAddressCountry',
122
                _t('DMSDocumentCartCheckoutPage.RECEIVER_COUNTRY', 'Country')
123
            )->setValue('NZ')
124
        );
125
126
        $form = DMSDocumentRequestForm::create($this, 'DMSDocumentRequestForm', $fields, FieldList::create());
127
        if ($receiverInfo = $this->getCart()->getReceiverInfo()) {
128
            $form->loadDataFrom($receiverInfo);
129
        }
130
131
        if ($message = $this->request->getVar('message')) {
0 ignored issues
show
Unused Code introduced by
$message is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
132
            $form->sessionMessage($this->ThanksMessage, 'good');
133
        } else {
134
            $form->clearMessage();
135
        }
136
        $this->extend('updateDMSDocumentRequestForm', $form);
137
138
        return $form;
139
    }
140
141
    /**
142
     * Sends an email to both the configured recipient as well as the requester. The
143
     * configured recipient is bcc'ed to the email in order to fulfill it.
144
     *
145
     * To extend use the following from within an Extension subclass:
146
     *
147
     * <code>
148
     * public function updateSend($email)
149
     * {
150
     *     // Do something here
151
     * }
152
     * </code>
153
     * @return mixed
154
     *
155
     * @throws DMSDocumentCartException
156
     */
157
    public function send()
158
    {
159
        $member = $this->CartEmailRecipient();
160
        if ($member->exists()) {
161
            $cart = $this->getCart();
162
            $from = Config::inst()->get('Email', 'admin_email');
163
            $emailAddress = ($info = $cart->getReceiverInfo()) ? $info['ReceiverEmail'] : $from;
164
            $email = Email::create(
165
                $from,
166
                $emailAddress,
167
                _t('DMSDocumentCartCheckoutPage.EMAIL_SUBJECT', 'Request for Printed Publications')
168
            );
169
            $email->setBcc($member->Email);
170
            $renderedCart = $cart->renderWith('DocumentCart_email');
171
            $body = _t(
172
                'DMSDocumentCartCheckoutPage.EMAIL_BODY',
173
                '<p>A request for printed publications has been submitted with the following details:</p>'
174
            );
175
            $body .= $renderedCart->getValue();
176
            $email->setBody($body)->setReplyTo($emailAddress);
177
            $this->extend('updateSend', $email);
178
            return $email->send();
179
        } else {
180
            throw new DMSDocumentCartException('No recipient has been configured. Please do so from the CMS');
181
        }
182
    }
183
184
    /**
185
     * Handles form submission.
186
     * Totals requested are updated, delivery details added, email sent for fulfillment
187
     * and print request totals updated.
188
     *
189
     * @param array          $data
190
     * @param Form           $form
191
     * @param SS_HTTPRequest $request
192
     *
193
     * @return SS_HTTPResponse
194
     */
195
    public function doRequestSend($data, Form $form, SS_HTTPRequest $request)
196
    {
197
        $this->updateCartItems($data);
198
        $this->updateCartReceiverInfo($data);
199
        $this->send();
200
        $this->trackTimestampedPrintRequest();
201
        $this->getCart()->saveSubmission($form);
202
        $this->getCart()->emptyCart();
203
        return $this->redirect("{$this->Link()}?message=1");
204
    }
205
206
    /**
207
     * Increments the print counts of all documents which were successfully sent.
208
     */
209
    public function trackTimestampedPrintRequest()
210
    {
211
        /** @var DMSRequestItem $item */
212
        foreach ($this->getCart()->getItems() as $item) {
213
            /** @var DMSDocument|DMSDocumentCartExtension $doc */
214
            $doc = $item->getDocument();
215
            $doc->incrementPrintRequest();
0 ignored issues
show
Bug introduced by
The method incrementPrintRequest does only exist in DMSDocumentCartExtension, but not in DMSDocument.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
216
        }
217
    }
218
219
    /**
220
     * Retrieves a {@link DMSDocumentCart} instance
221
     *
222
     * @return DMSDocumentCart
223
     */
224
    public function getCart()
225
    {
226
        return singleton('DMSDocumentCart');
227
    }
228
229
    /**
230
     * Updates the document quantities just before the request is sent.
231
     *
232
     * @param array $data
233
     */
234
    public function updateCartItems($data)
235
    {
236
        if (isset($data['ItemQuantity']) && !empty($data['ItemQuantity'])) {
237
            foreach ($data['ItemQuantity'] as $itemID => $quantity) {
238
                // Only update if quantity has changed
239
                $item = $this->getCart()->getItem($itemID);
240
                if ($item->getQuantity() == $quantity) {
241
                    continue;
242
                }
243
                $this->getCart()->updateItemQuantity($itemID, $quantity - 1);
244
            }
245
        }
246
    }
247
248
    /**
249
     * Updates the cart receiver info just before the request is sent.
250
     *
251
     * @param array          $data
252
     */
253
    public function updateCartReceiverInfo($data)
254
    {
255
        $info = array_merge(self::$receiverInfo, $data);
256
        $this->getCart()->setReceiverInfo($info);
257
    }
258
}
259