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

src/Cart/ShoppingCartController.php (1 issue)

Checks if properties have been declared.

Bug Major
1
<?php
2
3
namespace SilverShop\Cart;
4
5
use SilverShop\Extension\ViewableCartExtension;
6
use SilverShop\Model\Buyable;
7
use SilverShop\Model\Variation\Variation;
8
use SilverShop\Page\CartPage;
9
use SilverShop\Page\Product;
10
use SilverShop\ShopTools;
11
use SilverStripe\Control\Controller;
12
use SilverStripe\Control\Director;
13
use SilverStripe\Control\HTTPRequest;
14
use SilverStripe\Control\HTTPResponse;
15
use SilverStripe\Core\ClassInfo;
16
use SilverStripe\Dev\Debug;
17
use SilverStripe\ErrorPage\ErrorPage;
18
use SilverStripe\ORM\DataObject;
19
use SilverStripe\Security\Permission;
20
use SilverStripe\Security\SecurityToken;
21
use SilverStripe\Versioned\Versioned;
22
use SilverStripe\View\Requirements;
23
24
/**
25
 * Manipulate the cart via urls.
26
 *
27
 * @mixin  ViewableCartExtension
28
 * @method ShoppingCart Cart()
29
 */
30
class ShoppingCartController extends Controller
31
{
32
    private static $url_segment = 'shoppingcart';
33
34
    /**
35
     * Whether or not this controller redirects to the cart-page whenever an item was added
36
     *
37
     * @config
38
     * @var    bool
39
     */
40
    private static $direct_to_cart_page = false;
41
42
    /**
43
     * @var ShoppingCart
44
     */
45
    protected $cart;
46
47
    /**
48
     * @config
49
     * @var array
50
     */
51
    private static $url_handlers = [
52
        '$Action/$Buyable/$ID' => 'handleAction',
53
    ];
54
55
    /**
56
     * @config
57
     * @var array
58
     */
59
    private static $allowed_actions = [
60
        'add',
61
        'additem',
62
        'remove',
63
        'removeitem',
64
        'removeall',
65
        'removeallitem',
66
        'setquantity',
67
        'setquantityitem',
68
        'clear',
69
        'debug',
70
    ];
71
72
    public static function add_item_link(Buyable $buyable, $parameters = array())
73
    {
74
        return self::build_url('add', $buyable, $parameters);
75
    }
76
77
    public static function remove_item_link(Buyable $buyable, $parameters = array())
78
    {
79
        return self::build_url('remove', $buyable, $parameters);
80
    }
81
82
    public static function remove_all_item_link(Buyable $buyable, $parameters = array())
83
    {
84
        return self::build_url('removeall', $buyable, $parameters);
85
    }
86
87
    public static function set_quantity_item_link(Buyable $buyable, $parameters = array())
88
    {
89
        return self::build_url('setquantity', $buyable, $parameters);
90
    }
91
92
    /**
93
     * Helper for creating a url
94
     */
95
    protected static function build_url($action, $buyable, $params = [])
96
    {
97
        if (!$action || !$buyable) {
98
            return false;
99
        }
100
101
        if (SecurityToken::is_enabled() && !self::config()->disable_security_token) {
102
            $params[SecurityToken::inst()->getName()] = SecurityToken::inst()->getValue();
103
        }
104
105
        $className = get_class($buyable);
106
107
        $link = Controller::join_links(
108
            [
109
            self::config()->url_segment,
110
            $action,
111
            ShopTools::sanitiseClassName($className),
112
            $buyable->ID
113
            ]
114
        );
115
116
        return empty($params) ? $link : $link . '?' . http_build_query($params);
117
    }
118
119
    /**
120
     * This is used here and in VariationForm and AddProductForm
121
     *
122
     * @param bool|string $status
123
     *
124
     * @return string|HTTPResponse
125
     */
126
    public static function direct($status = true)
127
    {
128
        if (Director::is_ajax()) {
129
            return (string)$status;
130
        }
131
        if (self::config()->direct_to_cart_page && ($cartlink = CartPage::find_link())) {
132
            return Controller::curr()->redirect($cartlink);
133
        } else {
134
            return Controller::curr()->redirectBack();
135
        }
136
    }
137
138
    public function init()
139
    {
140
        parent::init();
141
        $this->cart = ShoppingCart::singleton();
142
    }
143
144
    /**
145
     * @return Product|Variation|Buyable
146
     * @throws \SilverStripe\Control\HTTPResponse_Exception
147
     */
148
    protected function buyableFromRequest()
149
    {
150
        $request = $this->getRequest();
151
        if (SecurityToken::is_enabled()
152
            && !self::config()->disable_security_token
153
            && !SecurityToken::inst()->checkRequest($request)
154
        ) {
155
            return $this->httpError(
156
                400,
157
                _t(
158
                    'SilverShop\Cart\ShoppingCart.InvalidSecurityToken',
159
                    'Invalid security token, possible CSRF attack.'
160
                )
161
            );
162
        }
163
        $id = (int)$request->param('ID');
164
        if (empty($id)) {
165
            //TODO: store error message
166
            return null;
167
        }
168
        $buyableclass = Product::class;
169
        if ($class = $request->param('Buyable')) {
170
            $buyableclass = ShopTools::unsanitiseClassName($class);
171
        }
172
        if (!ClassInfo::exists($buyableclass)) {
173
            //TODO: store error message
174
            return null;
175
        }
176
        //ensure only live products are returned, if they are versioned
177
        $buyable = $buyableclass::has_extension(Versioned::class)
178
            ? Versioned::get_by_stage($buyableclass, 'Live')->byID($id)
179
            : DataObject::get($buyableclass)->byID($id);
180
181
        if (!$buyable || !($buyable instanceof Buyable)) {
182
            //TODO: store error message
183
            return null;
184
        }
185
186
        return $this->cart->getCorrectBuyable($buyable);
187
    }
188
189
    /**
190
     * Action: add item to cart
191
     *
192
     * @param HTTPRequest $request
193
     *
194
     * @return HTTPResponse
195
     * @throws \SilverStripe\Control\HTTPResponse_Exception
196
     */
197
    public function add($request)
198
    {
199
        $result = false;
200
201
        if ($product = $this->buyableFromRequest()) {
202
            $quantity = (int)$request->getVar('quantity');
203
            if (!$quantity) {
204
                $quantity = 1;
205
            }
206
            $result = $this->cart->add($product, $quantity, $request->getVars());
207
        }
208
209
        $this->updateLocale($request);
210
        $this->extend('updateAddResponse', $request, $response, $product, $quantity, $result);
211
        return $response ? $response : self::direct();
212
    }
213
214
    /**
215
     * Action: remove a certain number of items from the cart
216
     *
217
     * @param HTTPRequest $request
218
     *
219
     * @return HTTPResponse
220
     * @throws \SilverStripe\Control\HTTPResponse_Exception
221
     */
222
    public function remove($request)
223
    {
224
        if ($product = $this->buyableFromRequest()) {
225
            $this->cart->remove($product, $quantity = 1, $request->getVars());
226
        }
227
228
        $this->updateLocale($request);
229
        $this->extend('updateRemoveResponse', $request, $response, $product, $quantity);
230
        return $response ? $response : self::direct();
231
    }
232
233
    /**
234
     * Action: remove all of an item from the cart
235
     *
236
     * @param HTTPRequest $request
237
     *
238
     * @return HTTPResponse
239
     * @throws \SilverStripe\Control\HTTPResponse_Exception
240
     */
241
    public function removeall($request)
242
    {
243
        if ($product = $this->buyableFromRequest()) {
244
            $this->cart->remove($product, null, $request->getVars());
245
        }
246
247
        $this->updateLocale($request);
248
        $this->extend('updateRemoveAllResponse', $request, $response, $product);
249
        return $response ? $response : self::direct();
250
    }
251
252
    /**
253
     * Action: update the quantity of an item in the cart
254
     *
255
     * @param HTTPRequest $request
256
     *
257
     * @return HTTPResponse
258
     * @throws \SilverStripe\Control\HTTPResponse_Exception
259
     */
260
    public function setquantity($request)
261
    {
262
        $product = $this->buyableFromRequest();
263
        $quantity = (int)$request->getVar('quantity');
264
        if ($product) {
265
            $this->cart->setQuantity($product, $quantity, $request->getVars());
266
        }
267
268
        $this->updateLocale($request);
269
        $this->extend('updateSetQuantityResponse', $request, $response, $product, $quantity);
270
        return $response ? $response : self::direct();
271
    }
272
273
    /**
274
     * Action: clear the cart
275
     *
276
     * @param HTTPRequest $request
277
     *
278
     * @return HTTPResponse
279
     */
280
    public function clear($request)
281
    {
282
        $this->updateLocale($request);
283
        $this->cart->clear();
284
        $this->extend('updateClearResponse', $request, $response);
285
        return $response ? $response : self::direct();
286
    }
287
288
    /**
289
     * Handle index requests
290
     *
291
     * @throws \SilverStripe\Control\HTTPResponse_Exception
292
     */
293
    public function index()
294
    {
295
        if ($cart = $this->Cart()) {
296
            return $this->redirect($cart->CartLink);
0 ignored issues
show
The property CartLink does not seem to exist on SilverShop\Cart\ShoppingCart.
Loading history...
297
        } elseif ($response = ErrorPage::response_for(404)) {
298
            return $response;
299
        }
300
        return $this->httpError(404, _t('SilverShop\Cart\ShoppingCart.NoCartInitialised', 'no cart initialised'));
301
    }
302
303
    /**
304
     * Displays order info and cart contents.
305
     */
306
    public function debug()
307
    {
308
        if (Director::isDev() || Permission::check('ADMIN')) {
309
            //TODO: allow specifying a particular id to debug
310
            Requirements::css('silvershop/core: client/dist/css/cartdebug.css');
311
            $order = ShoppingCart::curr();
312
            $content = ($order)
313
                ? Debug::text($order)
314
                : 'Cart has not been created yet. Add a product.';
315
            return ['Content' => $content];
316
        }
317
    }
318
319
    /**
320
     * @param HTTPRequest $request
321
     */
322
    protected function updateLocale($request)
323
    {
324
        $order = $this->cart->current();
325
        if ($request && $request->isAjax() && $order) {
326
            ShopTools::install_locale($order->Locale);
327
        }
328
    }
329
}
330