Box::submitEditBox()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 8.8571
c 0
b 0
f 0
cc 6
eloc 8
nc 4
nop 0
1
<?php
2
3
/**
4
 * @package Packer
5
 * @author Iurii Makukh <[email protected]>
6
 * @copyright Copyright (c) 2018, Iurii Makukh
7
 * @license https://www.gnu.org/licenses/gpl.html GNU/GPLv3
8
 */
9
10
namespace gplcart\modules\packer\controllers;
11
12
use Exception;
13
use gplcart\core\controllers\backend\Controller;
14
use gplcart\core\models\Convertor as ConvertorModel;
15
use gplcart\core\models\Product as ProductModel;
16
use gplcart\modules\packer\models\Box as BoxModel;
17
use gplcart\modules\packer\models\Packer as PackerModel;
18
19
/**
20
 * Handles incoming requests and outputs data related to boxes
21
 */
22
class Box extends Controller
23
{
24
25
    /**
26
     * Box model class instance
27
     * @var \gplcart\modules\packer\models\Box $box
28
     */
29
    protected $box;
30
31
    /**
32
     * Packer model class instance
33
     * @var \gplcart\modules\packer\models\Packer $packer
34
     */
35
    protected $packer;
36
37
    /**
38
     * Product model class instance
39
     * @var \gplcart\core\models\Product $product
40
     */
41
    protected $product;
42
43
    /**
44
     * Convertor model class instance
45
     * @var \gplcart\core\models\Convertor $convertor
46
     */
47
    protected $convertor;
48
49
    /**
50
     * Pager limit
51
     * @var array
52
     */
53
    protected $data_limit;
54
55
    /**
56
     * The current updating box
57
     * @var array
58
     */
59
    protected $data_box = array();
60
61
    /**
62
     * Box constructor.
63
     * @param BoxModel $box
64
     * @param PackerModel $packer
65
     * @param ProductModel $product
66
     * @param ConvertorModel $convertor
67
     */
68
    public function __construct(BoxModel $box, PackerModel $packer, ProductModel $product, ConvertorModel $convertor)
69
    {
70
        parent::__construct();
71
72
        $this->box = $box;
73
        $this->packer = $packer;
74
        $this->product = $product;
75
        $this->convertor = $convertor;
76
    }
77
78
    /**
79
     * Route callback
80
     * Displays the box overview page
81
     */
82
    public function listBox()
83
    {
84
        $this->actionListBox();
85
        $this->setTitleListBox();
86
        $this->setBreadcrumbListBox();
87
        $this->setFilterListBox();
88
        $this->setPagerListBox();
89
90
        $this->setData('boxes', $this->getListBox());
91
        $this->outputListBox();
92
    }
93
94
    /**
95
     * Applies an action to the selected boxes
96
     */
97
    protected function actionListBox()
98
    {
99
        list($selected, $action) = $this->getPostedAction();
100
101
        $deleted = 0;
102
103
        foreach ($selected as $id) {
104
            if ($action === 'delete' && $this->access('module_packer_box_delete')) {
105
                $deleted += (int) $this->box->delete($id);
106
            }
107
        }
108
109
        if ($deleted > 0) {
110
            $message = $this->text('Deleted %num item(s)', array('%num' => $deleted));
111
            $this->setMessage($message, 'success');
112
        }
113
    }
114
115
    /**
116
     * Sets filter parameters on the box overview page
117
     */
118
    protected function setFilterListBox()
119
    {
120
        $filter = array(
121
            'created', 'name', 'box_id',
122
            'status', 'inner_width', 'inner_length',
123
            'inner_depth', 'max_weight', 'weight_unit',
124
            'size_unit', 'shipping_method'
125
        );
126
127
        $this->setFilter($filter);
128
    }
129
130
    /**
131
     * Sets pager on the box overview page
132
     * @return array
133
     */
134
    protected function setPagerListBox()
135
    {
136
        $options = $this->query_filter;
137
        $options['count'] = true;
138
139
        $pager = array(
140
            'query' => $this->query_filter,
141
            'total' => (int) $this->box->getList($options)
142
        );
143
144
        return $this->data_limit = $this->setPager($pager);
145
    }
146
147
    /**
148
     * Returns an array of boxes
149
     * @return array
150
     */
151
    protected function getListBox()
152
    {
153
        $options = $this->query_filter;
154
        $options['limit'] = $this->data_limit;
155
156
        return $this->box->getList($options);
157
    }
158
159
    /**
160
     * Sets title on the box overview page
161
     */
162
    protected function setTitleListBox()
163
    {
164
        $this->setTitle($this->text('Boxes'));
165
    }
166
167
    /**
168
     * Sets breadcrumbs on the box overview page
169
     */
170
    protected function setBreadcrumbListBox()
171
    {
172
        $breadcrumb = array(
173
            'url' => $this->url('admin'),
174
            'text' => $this->text('Dashboard')
175
        );
176
177
        $this->setBreadcrumb($breadcrumb);
178
    }
179
180
    /**
181
     * Render and output the box overview page
182
     */
183
    protected function outputListBox()
184
    {
185
        $this->output('packer|box/list');
186
    }
187
188
    /**
189
     * Page callback
190
     * Displays the fit items page
191
     * @param $box_id
192
     */
193
    public function fitBox($box_id)
194
    {
195
        $this->setBox((int) $box_id);
196
        $this->setTitleFitBox();
197
        $this->setBreadcrumbEditBox();
198
199
        $this->setData('box', $this->data_box);
200
201
        $this->submitFitBox();
202
        $this->setDataFitBox();
203
        $this->outputFitBox();
204
    }
205
206
    /**
207
     * Prepare and set variables for template
208
     */
209
    protected function setDataFitBox()
210
    {
211
        $product_id = $this->getData('box.product_id');
212
213
        if (is_array($product_id)) {
214
            $this->setData('box.product_id', implode(PHP_EOL, $product_id));
215
        }
216
    }
217
218
219
    /**
220
     * Sets titles on the fit box page
221
     */
222
    protected function setTitleFitBox()
223
    {
224
        $text = $this->text('Fit products into box %name', array('%name' => $this->data_box['name']));
225
        $this->setTitle($text);
226
    }
227
228
    /**
229
     * Handles submitted data while trying to fit products into a box
230
     */
231
    protected function submitFitBox()
232
    {
233
        if ($this->isPosted('fit') && $this->validateFitBox()) {
234
            $this->doFitBox();
235
        }
236
    }
237
238
    /**
239
     * Validates submitted data while trying to fit products into a box
240
     * @return bool
241
     */
242
    protected function validateFitBox()
243
    {
244
        $this->setSubmitted('box');
245
        $this->setSubmittedArray('product_id');
246
        $this->validateElement('product_id', 'required');
247
        $this->validateProductsFitBox();
248
249
        return !$this->hasErrors();
250
    }
251
252
    /**
253
     * Validates an array of submitted product IDs
254
     */
255
    protected function validateProductsFitBox()
256
    {
257
        $errors = $products = array();
258
259
        foreach ((array) $this->getSubmitted('product_id', array()) as $line => $product_id) {
260
261
            $line++;
262
263
            if (!is_numeric($product_id)) {
264
                $errors[] = $this->text('Error on line @num: @error', array(
265
                    '@num' => $line,
266
                    '@error' => $this->text('Product ID must be numeric')));
267
                continue;
268
            }
269
270
            $product = $this->product->get($product_id);
271
272
            if (empty($product)) {
273
                $errors[] = $this->text('Error on line @num: @error', array(
274
                    '@num' => $line,
275
                    '@error' => $this->text('Product does not exist')));
276
                continue;
277
            }
278
279
            if (empty($product['length']) || empty($product['width']) || empty($product['height'])) {
280
                $errors[] = $this->text('Error on line @num: @error', array(
281
                    '@num' => $line,
282
                    '@error' => $this->text('At least one dimension parameter is undefined')));
283
                continue;
284
            }
285
286
            if (empty($product['weight'])) {
287
                $errors[] = $this->text('Error on line @num: @error', array(
288
                    '@num' => $line,
289
                    '@error' => $this->text('Unknown weight')));
290
                continue;
291
            }
292
293
            $products[] = $product;
294
        }
295
296
        if (!empty($errors)) {
297
            $this->setError('product_id', $errors);
298
        }
299
300
        $this->setSubmitted('products', $products);
301
    }
302
303
    /**
304
     * Tries to fit the submitted products into a box
305
     */
306
    protected function doFitBox()
307
    {
308
        try {
309
            $products = $this->getSubmitted('products');
310
            $items = $this->packer->getFitItems($products, $this->data_box);
311
        } catch (Exception $ex) {
312
            $items = array();
313
            $this->setMessage($ex->getMessage(), 'warning');
314
        }
315
316
        if (empty($items)) {
317
            $this->setMessage($this->text('Nothing fits into the box'));
318
        } else {
319
            $this->setData('items', $items);
320
        }
321
322
        $this->setData('box.product_id', $this->getSubmitted('product_id'));
323
    }
324
325
    /**
326
     * Render and output the box fit items page
327
     */
328
    protected function outputFitBox()
329
    {
330
        $this->output('packer|box/fit');
331
    }
332
333
334
    /**
335
     * Page callback
336
     * Displays the edit box page
337
     * @param null|int $box_id
338
     */
339
    public function editBox($box_id = null)
340
    {
341
        $this->setBox($box_id);
342
        $this->setTitleEditBox();
343
        $this->setBreadcrumbEditBox();
344
345
        $this->setData('box', $this->data_box);
346
        $this->setData('fields', $this->getDimensionFieldsBox());
347
        $this->setData('size_units', $this->convertor->getUnitNames('size'));
348
        $this->setData('weight_units', $this->convertor->getUnitNames('weight'));
349
350
        $this->submitEditBox();
351
        $this->outputEditBox();
352
    }
353
354
    /**
355
     * Sets the box data
356
     * @param $box_id
357
     */
358
    protected function setBox($box_id)
359
    {
360
        if (is_numeric($box_id)) {
361
            $this->data_box = $this->box->get($box_id);
362
            if (empty($this->data_box)) {
363
                $this->outputHttpStatus(403);
364
            }
365
        }
366
    }
367
368
    /**
369
     * Sets titles on the edit box page
370
     */
371
    protected function setTitleEditBox()
372
    {
373
        if (isset($this->data_box['box_id'])) {
374
            $text = $this->text('Edit %name', array('%name' => $this->data_box['box_id']));
375
        } else {
376
            $text = $this->text('Add box');
377
        }
378
379
        $this->setTitle($text);
380
    }
381
382
    /**
383
     * Sets breadcrumbs on the box edit page
384
     */
385
    protected function setBreadcrumbEditBox()
386
    {
387
        $breadcrumbs = array();
388
389
        $breadcrumbs[] = array(
390
            'url' => $this->url('admin'),
391
            'text' => $this->text('Dashboard')
392
        );
393
394
        $breadcrumbs[] = array(
395
            'url' => $this->url('admin/settings/box'),
396
            'text' => $this->text('Boxes')
397
        );
398
399
        $this->setBreadcrumbs($breadcrumbs);
400
    }
401
402
    /**
403
     * Handles a submitted box
404
     */
405
    protected function submitEditBox()
406
    {
407
        if ($this->isPosted('delete') && isset($this->data_box['box_id'])) {
408
            $this->deleteBox();
409
        } else if ($this->isPosted('save') && $this->validateEditBox()) {
410
            if (isset($this->data_box['box_id'])) {
411
                $this->updateBox();
412
            } else {
413
                $this->addBox();
414
            }
415
        }
416
    }
417
418
    /**
419
     * Validates a submitted box data
420
     */
421
    protected function validateEditBox()
422
    {
423
        $this->setSubmitted('box');
424
        $this->setSubmittedBool('status');
425
426
        $this->validateElement('name', 'length', array(1, 255));
427
        $this->validateElement('shipping_method', 'length', array(0, 255));
428
429
        foreach (array_keys($this->getDimensionFieldsBox()) as $field) {
430
            $this->validateElement($field, 'numeric');
431
            $this->validateElement($field, 'length', array(1, 10));
432
        }
433
434
        $unit = $this->getSubmitted('size_unit');
435
        $units = $this->convertor->getUnitNames('size');
436
437
        if (empty($unit) || empty($units[$unit])) {
438
            $this->setError('size_unit', $this->text('Invalid size measurement unit'));
439
        }
440
441
        $unit = $this->getSubmitted('weight_unit');
442
        $units = $this->convertor->getUnitNames('weight');
443
444
        if (empty($unit) || empty($units[$unit])) {
445
            $this->setError('weight_unit', $this->text('Invalid weight measurement unit'));
446
        }
447
448
        return !$this->hasErrors();
449
    }
450
451
    /**
452
     * Returns an array of box dimension field names keyed by DB fields
453
     * @return array
454
     */
455
    protected function getDimensionFieldsBox()
456
    {
457
        $fields = array('outer_width', 'outer_length',
458
            'outer_depth', 'empty_weight', 'inner_width',
459
            'inner_width', 'inner_length', 'inner_depth', 'max_weight');
460
461
        $names = array();
462
463
        foreach ($fields as $field) {
464
            $names[$field] = ucfirst(str_replace('_', ' ', $field));
465
        }
466
467
        return $names;
468
    }
469
470
    /**
471
     * Updates a submitted box
472
     */
473
    protected function updateBox()
474
    {
475
        $this->controlAccess('module_packer_box_edit');
476
477
        if ($this->box->update($this->data_box['box_id'], $this->getSubmitted())) {
478
            $this->redirect('admin/settings/box', $this->text('Box has been updated'), 'success');
479
        }
480
481
        $this->redirect('', $this->text('Box has not been updated'), 'warning');
482
    }
483
484
    /**
485
     * Adds a new box
486
     */
487
    protected function addBox()
488
    {
489
        $this->controlAccess('module_packer_box_add');
490
491
        if ($this->box->add($this->getSubmitted())) {
492
            $this->redirect('admin/settings/box', $this->text('Box has been added'), 'success');
493
        }
494
495
        $this->redirect('', $this->text('Box has not been added'), 'warning');
496
    }
497
498
    /**
499
     * Delete a submitted box
500
     */
501
    protected function deleteBox()
502
    {
503
        $this->controlAccess('module_packer_box_delete');
504
505
        if ($this->box->delete($this->data_box['box_id'])) {
506
            $this->redirect('admin/settings/box', $this->text('Box has been deleted'), 'success');
507
        }
508
509
        $this->redirect('', $this->text('Box has not been deleted'), 'warning');
510
    }
511
512
    /**
513
     * Render and output the box edit page
514
     */
515
    protected function outputEditBox()
516
    {
517
        $this->output('packer|box/edit');
518
    }
519
520
}
521