GiftVoucherProductPage   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 130
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 9

Importance

Changes 0
Metric Value
wmc 7
lcom 0
cbo 9
dl 0
loc 130
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A i18n_singular_name() 0 4 1
A i18n_plural_name() 0 4 1
A canCreate() 0 4 2
A canPurchase() 0 4 1
B getCMSFields() 0 44 2
1
<?php
2
/**
3
 * @author nicolaas [at] sunnysideup.co.nz
4
 * @requires ecommerce
5
 * @requires ecommerce_product_variation
6
 */
7
class GiftVoucherProductPage extends Product
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...
8
{
9
    private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
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...
10
        'DescriptionFieldLabel' => 'Varchar(255)',
11
        'AmountFieldLabel' => 'Varchar(255)',
12
        'ActionFieldLabel' => 'Varchar(255)',
13
        'MinimumAmount' => 'Decimal(9,2)',
14
        'MaximumAmount' => 'Decimal(9,2)',
15
        'RecommendedAmounts' => 'Varchar(255)',
16
        'CanSetDescription' => 'Boolean',
17
        'DefaultDescription' => 'Varchar(255)',
18
    );
19
20
    private static $defaults = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
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...
21
        'DescriptionFieldLabel' => 'Enter Description',
22
        'AmountFieldLabel' => 'Enter Amount',
23
        'ActionFieldLabel' => 'Add to cart',
24
        'MinimumAmount' => 1,
25
        'MaximumAmount' => 100,
26
        'AllowPurchase' => false,
27
        'Price' => 0,
28
    );
29
30
    private static $field_labels = array(
0 ignored issues
show
Unused Code introduced by
The property $field_labels 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...
31
        'DescriptionFieldLabel' => 'Description Label',
32
        'AmountFieldLabel' => 'Amount Label',
33
        'ActionFieldLabel' => 'Button Label',
34
        'MinimumAmount' => 'Minimum Amount',
35
        'MaximumAmount' => 'Maximum Amount',
36
        'RecommendedAmounts' => 'Hinted amounts',
37
        'CanSetDescription' => 'Customer Adds Description',
38
        'DefaultDescription' => 'Default Description',
39
    );
40
41
    private static $field_labels_right = array(
0 ignored issues
show
Unused Code introduced by
The property $field_labels_right 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...
42
        'DescriptionFieldLabel' => 'e.g. please enter title for payment',
43
        'AmountFieldLabel' => 'e.g. please enter amount for payment',
44
        'ActionFieldLabel' => 'e.g. pay now',
45
        'MinimumAmount' => 'e.g. 10.00',
46
        'MaximumAmount' => 'e.g. 100.00',
47
        'RecommendedAmounts' => 'create a list of recommended payment amounts, separated by a space, e.g. 10.00 12.00 19.00 23.00',
48
        'CanSetDescription' => 'can the customer add their own description to the payment?',
49
        'DefaultDescription' => 'e.g. generic product, this field is optional',
50
    );
51
52
    private static $singular_name = 'Any Price Product';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $singular_name 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...
53
    public function i18n_singular_name()
54
    {
55
        return _t('GiftVoucherProductPage.GIFT_VOUCHER_PRODUCT_PAGE', 'Gift Voucher Page');
56
    }
57
58
    private static $plural_name = 'Any Price Products';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $plural_name 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...
59
    public function i18n_plural_name()
60
    {
61
        return _t('GiftVoucherProductPage.GIFT_VOUCHER_PRODUCT_PAGES', 'Gift Voucher Pages');
62
    }
63
64
    private static $icon = 'ecommerce_giftvoucher/images/treeicons/GiftVoucherProductPage';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $icon 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...
65
66
    /**
67
     * @config
68
     *
69
     * @var string Description of the class functionality, typically shown to a user
70
     *             when selecting which page type to create. Translated through {@link provideI18nEntities()}.
71
     */
72
    private static $description = 'Generic product that can be used to allow customers to choose a specific amount to pay.';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $description 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...
73
74
    public function canCreate($member = null)
75
    {
76
        return SiteTree::get()->filter(array('ClassName' => 'GiftVoucherProductPage'))->count() ? false : true;
77
    }
78
79
80
    public function canPurchase(Member $member = null, $checkPrice = true)
81
    {
82
        return parent::canPurchase($member, false);
83
    }
84
85
86
87
    /**
88
     * @var string
89
     */
90
    protected $defaultClassNameForOrderItem = 'GiftVoucherProductPage_ProductOrderItem';
91
92
    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...
93
    {
94
        $fields = parent::getCMSFields();
95
        $fieldLabels = $this->fieldLabels();
96
        $fieldLabelsRight = Config::inst()->get('GiftVoucherProductPage', 'field_labels_right');
97
        $exampleLink = Director::absoluteURL($this->Link('setamount')).'/123.45/?description='.urlencode('test payment only');
98
        $exampleLinkExplanation = sprintf(_t('GiftVoucherProductPage.EXPLANATION', '<br /><br /><h5>How to preset the amount?</h5><p>The link <a href="%1$s">%1$s</a> will pre-set the amount to 123.45. You can use this link (and vary the amount as needed) to cutomers to receive payments.</p>.'), $exampleLink);
99
        $fields->addFieldsToTab(
100
            'Root.Form',
101
            array(
102
                TextField::create('DescriptionFieldLabel', $fieldLabels['DescriptionFieldLabel'])->setDescription($fieldLabelsRight['DescriptionFieldLabel']),
103
                TextField::create('AmountFieldLabel', $fieldLabels['AmountFieldLabel'])->setDescription($fieldLabelsRight['AmountFieldLabel']),
104
                TextField::create('ActionFieldLabel', $fieldLabels['ActionFieldLabel'])->setDescription($fieldLabelsRight['ActionFieldLabel']),
105
                NumericField::create('MinimumAmount', $fieldLabels['MinimumAmount'])->setDescription($fieldLabelsRight['MinimumAmount']),
106
                NumericField::create('MaximumAmount', $fieldLabels['MaximumAmount'])->setDescription($fieldLabelsRight['MaximumAmount']),
107
                TextField::create('RecommendedAmounts', $fieldLabels['RecommendedAmounts'])->setDescription($fieldLabelsRight['RecommendedAmounts']),
108
                CheckboxField::create('CanSetDescription', $fieldLabels['CanSetDescription'])->setDescription($fieldLabelsRight['CanSetDescription']),
109
                TextField::create('DefaultDescription', $fieldLabels['DefaultDescription'])->setDescription($fieldLabelsRight['DefaultDescription']),
110
                LiteralField::create('ExampleLinkExplanation', $exampleLinkExplanation),
111
            )
112
        );
113
        if (!$this->CanSetDescription) {
114
            $fields->removeByName('DescriptionFieldLabel');
115
        }
116
        // Standard product detail fields
117
        $fields->removeFieldsFromTab(
118
            'Root.Details',
119
            array(
120
                'Weight',
121
                'Price',
122
                'Model',
123
            )
124
        );
125
126
        // Flags for this product which affect it's behaviour on the site
127
        $fields->removeFieldsFromTab(
128
            'Root.Details',
129
            array(
130
                'FeaturedProduct',
131
            )
132
        );
133
134
        return $fields;
135
    }
136
}
137
138
class GiftVoucherProductPage_Controller extends Product_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...
139
{
140
    private static $allowed_actions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
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...
141
        'AddNewPriceForm',
142
        'doaddnewpriceform',
143
        'setamount'
144
    );
145
146
    public function AddNewPriceForm()
147
    {
148
        if ($this->canPurchase()) {
149
            $requiredFields = array();
150
            $amount = $this->MinimumAmount;
151
            if ($newAmount = Session::get('GiftVoucherProductPageAmount')) {
152
                $amount = $newAmount;
153
            }
154
            $description = $this->DefaultDescription;
155
            if ($newDescription = Session::get('GiftVoucherProductPageDescription')) {
156
                $description = $newDescription;
157
            }
158
            $fields = FieldList::create();
159
            if ($this->CanSetDescription) {
160
                $fields->push(TextField::create('Description', $this->DescriptionFieldLabel, $description));
161
                $requiredFields[] = 'Description';
162
            }
163
            $fields->push(CurrencyField::create('Amount', $this->AmountFieldLabel, $amount));
164
            $requiredFields[] = 'Amount';
165
166
            $actions = FieldList::create(
167
                FormAction::create('doaddnewpriceform', $this->ActionFieldLabel)
168
            );
169
            $requiredFields = RequiredFields::create($requiredFields);
170
171
            return Form::create(
172
                $controller = $this,
173
                $name = 'AddNewPriceForm',
174
                $fields,
175
                $actions,
176
                $requiredFields
177
            );
178
        }
179
    }
180
181
    public function doaddnewpriceform($data, $form)
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...
182
    {
183
        //check amount
184
        $amount = $this->parseFloat($data['Amount']);
185
        if ($this->MinimumAmount > 0 && ($amount < $this->MinimumAmount)) {
186
            $form->sessionMessage(_t('GiftVoucherProductPage.ERRORINFORMTOOLOW', 'Please enter a higher amount.'), 'bad');
187
            $this->redirectBack();
188
189
            return;
190
        } elseif ($this->MaximumAmount > 0 && ($amount > $this->MaximumAmount)) {
191
            $form->sessionMessage(_t('GiftVoucherProductPage.ERRORINFORMTOOHIGH', 'Please enter a lower amount.'), 'bad');
192
            $this->redirectBack();
193
194
            return;
195
        }
196
197
        //clear settings from URL
198
        Session::clear('GiftVoucherProductPageAmount');
199
        Session::clear('GiftVoucherProductPageDescription');
200
201
        //create a description
202
        if (isset($data['Description']) && $data['Description']) {
203
            $description = Convert::raw2sql($data['Description']);
204
        } elseif ($this->DefaultDescription) {
205
            $description = $this->DefaultDescription;
206
        } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
207
            //..
208
        }
209
210
        //create order item and update it ... if needed
211
        $orderItem = $this->createOrderItem($amount, $description, $data);
0 ignored issues
show
Bug introduced by
The variable $description does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
212
        $orderItem = $this->updateOrderItem($orderItem, $data, $form);
213
214
        if (! $orderItem) {
215
            $form->sessionMessage(_t('GiftVoucherProductPage.ERROROTHER', 'Sorry, we could not add your entry.'), 'bad');
216
            $this->redirectBack();
217
218
            return;
219
        }
220
        $checkoutPage = CheckoutPage::get()->First();
221
        if ($checkoutPage) {
222
            return $this->redirect($checkoutPage->Link());
223
        }
224
        return array();
225
    }
226
227
    public function setamount($request)
0 ignored issues
show
Coding Style introduced by
setamount uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
228
    {
229
        if ($amount = floatval($request->param('ID'))) {
230
            Session::set('GiftVoucherProductPageAmount', $amount);
231
        }
232
        if ($description = Convert::raw2sql($request->param('OtherID'))) {
0 ignored issues
show
Unused Code introduced by
$description 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...
233
            Session::set('GiftVoucherProductPageDescription', $_GET['description']);
234
        }
235
        $this->redirect($this->Link());
236
237
        return array();
238
    }
239
240
    /**
241
     * clean up the amount, we may improve this in the future.
242
     *
243
     * @return float
244
     */
245
    protected function parseFloat($floatString)
246
    {
247
        return preg_replace('/([^0-9\\.])/i', '', $floatString);
248
    }
249
250
    /**
251
     * @param Variation (optional) $variation
252
     * @return OrderItem | null
253
     */
254
    protected function createOrderItem($amount, $description, $data)
255
    {
256
        $shoppingCart = ShoppingCart::singleton();
257
        $orderItem = $shoppingCart->addBuyable($this->dataRecord);
258
        $orderItem->setCustomCalculatedTotal($amount);
259
        $orderItem->setCustomDescription($description);
260
        return $orderItem;
261
    }
262
263
    /**
264
     * you can add this method to a class extending
265
     * GiftVoucherProductPage_Controller so that you can do something with the OrderItem
266
     *
267
     * @param OrderItem $orderItem
268
     * @param array $data
269
     * @param Form $form
270
     *
271
     * @return OrderItem
272
     */
273
    protected function updateOrderItem($orderItem, $data, $form)
274
    {
275
        return $orderItem;
276
    }
277
}
278