Completed
Pull Request — 2.0 (#506)
by Roman
18:39
created

OrderItem   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 219
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 78.87%

Importance

Changes 3
Bugs 1 Features 1
Metric Value
wmc 32
c 3
b 1
f 1
lcom 1
cbo 3
dl 0
loc 219
ccs 56
cts 71
cp 0.7887
rs 9.6

16 Methods

Rating   Name   Duplication   Size   Complexity  
A Buyable() 0 4 1
A UnitPrice() 0 10 3
A setUnitPrice() 0 7 2
A setQuantity() 0 5 2
A Total() 0 7 2
A calculatetotal() 0 7 1
A uniquedata() 0 16 4
A onBeforeWrite() 0 7 4
A onPayment() 0 4 1
A onPlacement() 0 4 1
A Image() 0 6 2
A QuantityField() 0 4 1
A addLink() 0 5 2
A removeLink() 0 5 2
A removeallLink() 0 5 2
A setquantityLink() 0 5 2
1
<?php
2
3
/**
4
 * An order item is a product which has been added to an order,
5
 * ready for purchase. An order item is typically a product itself,
6
 * but also can include references to other information such as
7
 * product attributes like colour, size, or type.
8
 *
9
 * @package shop
10
 */
11
class OrderItem extends OrderAttribute
12
{
13
    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...
14
        'Quantity'  => 'Int',
15
        'UnitPrice' => 'Currency',
16
    );
17
18
    private static $casting              = 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...
19
        'UnitPrice' => 'Currency',
20
        'Total'     => 'Currency',
21
    );
22
23
    private static $searchable_fields    = 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...
24
        'OrderID'    => array(
25
            'title' => 'Order ID',
26
            'field' => 'TextField',
27
        ),
28
        "Title"      => "PartialMatchFilter",
29
        "TableTitle" => "PartialMatchFilter",
30
        "CartTitle"  => "PartialMatchFilter",
31
        "UnitPrice",
32
        "Quantity",
33
        "Total",
34
    );
35
36
    private static $summary_fields       = 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...
37
        "Order.ID"   => "Order ID",
38
        "TableTitle" => "Title",
39
        "UnitPrice"  => "Unit Price",
40
        "Quantity"   => "Quantity",
41
        "Total"      => "Total Price",
42
    );
43
44
    private static $required_fields      = array();
45
46
    private static $buyable_relationship = "Product";
47
48
    private static $singular_name        = "Item";
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...
49
50
    private static $plural_name          = "Items";
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...
51
52
    private static $default_sort         = "\"Created\" DESC";
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...
53
54
    /**
55
     * Get the buyable object related to this item.
56
     */
57 83
    public function Buyable()
58
    {
59 83
        return $this->{self::config()->buyable_relationship}();
60
    }
61
62
    /**
63
     * Get unit price for this item.
64
     * Fetches from db, or Buyable, based on order status.
65
     */
66 83
    public function UnitPrice()
67
    {
68 83
        if ($this->Order()->IsCart()) {
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<OrderItem>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
69 83
            $buyable = $this->Buyable();
70 83
            $unitprice = ($buyable) ? $buyable->sellingPrice() : $this->UnitPrice;
0 ignored issues
show
Documentation introduced by
The property UnitPrice does not exist on object<OrderItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
71 83
            $this->extend('updateUnitPrice', $unitprice);
72 83
            return $this->UnitPrice = $unitprice;
0 ignored issues
show
Documentation introduced by
The property UnitPrice does not exist on object<OrderItem>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
73
        }
74 4
        return $this->UnitPrice;
0 ignored issues
show
Documentation introduced by
The property UnitPrice does not exist on object<OrderItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
75
    }
76
77
    /**
78
     * Prevent unit price ever being below 0
79
     */
80 83
    public function setUnitPrice($val)
81
    {
82 83
        if ($val < 0) {
83
            $val = 0;
84
        }
85 83
        $this->setField("UnitPrice", $val);
86 83
    }
87
88
    /**
89
     * Prevent quantity being below 1.
90
     * 0 quantity means it should instead be deleted.
91
     *
92
     * @param int $val new quantity to set
93
     */
94 83
    public function setQuantity($val)
95
    {
96 83
        $val = $val < 1 ? 1 : $val;
97 83
        $this->setField("Quantity", $val);
98 83
    }
99
100
    /**
101
     * Get calculated total, or stored total
102
     * depending on whether the order is in cart
103
     */
104 15
    public function Total()
105
    {
106 15
        if ($this->Order()->IsCart()) { //always calculate total if order is in cart
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<OrderItem>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
107 10
            return $this->calculatetotal();
108
        }
109 5
        return $this->CalculatedTotal; //otherwise get value from database
0 ignored issues
show
Documentation introduced by
The property CalculatedTotal does not exist on object<OrderItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
110
    }
111
112
    /**
113
     * Calculates the total for this item.
114
     * Generally called by onBeforeWrite
115
     */
116 83
    protected function calculatetotal()
117
    {
118 83
        $total = $this->UnitPrice() * $this->Quantity;
0 ignored issues
show
Documentation introduced by
The property Quantity does not exist on object<OrderItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
119 83
        $this->extend('updateTotal', $total);
120 83
        $this->CalculatedTotal = $total;
0 ignored issues
show
Documentation introduced by
The property CalculatedTotal does not exist on object<OrderItem>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
121 83
        return $total;
122
    }
123
124
    /**
125
     * Intersects this item's required_fields with the data record.
126
     * This is used for uniquely adding items to the cart.
127
     */
128 1
    public function uniquedata()
129
    {
130 1
        $required = self::config()->required_fields; //TODO: also combine with all ancestors of this->class
131 1
        $data = $this->record;
0 ignored issues
show
Unused Code introduced by
$data 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 1
        $unique = array();
133
        //reduce record to only required fields
134 1
        if ($required) {
135
            foreach ($required as $field) {
136
                if ($this->has_one($field)) {
0 ignored issues
show
Deprecated Code introduced by
The method DataObject::has_one() has been deprecated with message: 4.0 Method has been replaced by hasOne() and hasOneComponent()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
137
                    $field = $field . "ID"; //add ID to hasones
138
                }
139
                $unique[$field] = $this->$field;
140
            }
141
        }
142 1
        return $unique;
143
    }
144
145
    /**
146
     * Recalculate total before saving to database.
147
     */
148 83
    public function onBeforeWrite()
149
    {
150 83
        parent::onBeforeWrite();
151 83
        if ($this->OrderID && $this->Order() && $this->Order()->isCart()) {
0 ignored issues
show
Documentation introduced by
The property OrderID does not exist on object<OrderItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation Bug introduced by
The method Order does not exist on object<OrderItem>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
152 83
            $this->calculatetotal();
153 83
        }
154 83
    }
155
156
    /*
157
     * Event handler called when an order is fully paid for.
158
     */
159
    public function onPayment()
160
    {
161
        $this->extend('onPayment');
162
    }
163
164
    /**
165
     * Event handlier called for last time saving/processing,
166
     * before item permanently stored in database.
167
     * This should only be called when order is transformed from
168
     * Cart to Order, aka being 'placed'.
169
     */
170 4
    public function onPlacement()
171
    {
172 4
        $this->extend('onPlacement');
173 4
    }
174
175
    /**
176
     * Get the buyable image.
177
     * Also serves as a standardised placeholder for overriding in subclasses.
178
     */
179 3
    public function Image()
180
    {
181 3
        if ($this->Buyable()) {
182 3
            return $this->Buyable()->Image();
183
        }
184
    }
185
186
    /**
187
     * @return ShopQuantityField
188
     */
189
    public function QuantityField()
190
    {
191
        return Injector::inst()->create('ShopQuantityField', $this);
192
    }
193
194
    /**
195
     * @return string
196
     */
197 1
    public function addLink()
198
    {
199 1
        $buyable = $this->Buyable();
200 1
        return $buyable ? ShoppingCart_Controller::add_item_link($buyable, $this->uniquedata()) : '';
201
    }
202
203
    /**
204
     * @return string
205
     */
206 2
    public function removeLink()
207
    {
208 2
        $buyable = $this->Buyable();
209 2
        return $buyable ? ShoppingCart_Controller::remove_item_link($buyable, $this->uniquedata()) : '';
210
    }
211
212
    /**
213
     * @return string
214
     */
215 1
    public function removeallLink()
216
    {
217 1
        $buyable = $this->Buyable();
218 1
        return $buyable ? ShoppingCart_Controller::remove_all_item_link($buyable, $this->uniquedata()) : '';
219
    }
220
221
    /**
222
     * @return string
223
     */
224 1
    public function setquantityLink()
225
    {
226 1
        $buyable = $this->Buyable();
227 1
        return $buyable ? ShoppingCart_Controller::set_quantity_item_link($buyable, $this->uniquedata()) : '';
228
    }
229
}
230