Passed
Pull Request — master (#429)
by
unknown
03:35
created

ReorderElements   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 38
dl 0
loc 75
rs 10
c 0
b 0
f 0
wmc 7

2 Methods

Rating   Name   Duplication   Size   Complexity  
A reorder() 0 54 5
A __construct() 0 9 2
1
<?php
2
3
namespace DNADesign\Elemental\Services;
4
5
use DNADesign\Elemental\Models\BaseElement;
6
use InvalidArgumentException;
7
use SilverStripe\Core\Convert;
8
use SilverStripe\ORM\DataObject;
9
use SilverStripe\ORM\Queries\SQLUpdate;
10
11
class ReorderElements
12
{
13
    /**
14
     * @var BaseElement $block
15
     */
16
    private $element;
17
18
    public function __construct(BaseElement $element)
19
    {
20
        if (!is_subclass_of($element, BaseElement::class)) {
21
            throw new InvalidArgumentException(sprintf(
22
                'Invalid ' . BaseElement::class . ' passed to ' . __CLASS__
23
            ));
24
        }
25
26
        $this->element = $element;
27
    }
28
29
    /**
30
     * @param
31
     */
32
    public function reorder($elementToBeAfterID = 0)
33
    {
34
        $element = $this->element;
35
        $parentId = $element->ParentID;
0 ignored issues
show
Bug Best Practice introduced by
The property ParentID does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
36
        $currentPosition = (int) $element->Sort;
37
        $sortAfterPosition = 0;
38
39
        if ($elementToBeAfterID) {
40
            /** @var BaseElement $afterBlock */
41
            $afterElement = BaseElement::get()->byID($elementToBeAfterID);
42
43
            if (!$afterElement) {
0 ignored issues
show
introduced by
$afterElement is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
44
                throw new InvalidArgumentException(sprintf(
45
                    '%s#%s not found',
46
                    BaseElement::class,
47
                    $elementToBeAfterID
48
                ));
49
            }
50
51
            if ($afterElement->ParentID !== $parentId) {
52
                throw new InvalidArgumentException(
53
                    'Trying to sort element to be placed after an element from a different elemental area'
54
                );
55
            }
56
57
            $sortAfterPosition = (int) $afterElement->Sort;
58
        }
59
60
        // We are updating records with SQL queries to avoid the ORM triggering the creation of new versions
61
        // for each element that is affected by this reordering.
62
        $tableName = Convert::raw2sql(DataObject::getSchema()->tableName(BaseElement::class));
63
64
        if ($sortAfterPosition < $currentPosition) {
65
            $operator = '+';
66
            $filter = "\"$tableName\".\"Sort\" > $sortAfterPosition AND \"$tableName\".\"Sort\" < $currentPosition";
67
            $newBlockPosition = $sortAfterPosition + 1;
68
        } else {
69
            $operator = '-';
70
            $filter = "\"$tableName\".\"Sort\" <= $sortAfterPosition AND \"$tableName\".\"Sort\" > $currentPosition";
71
            $newBlockPosition = $sortAfterPosition;
72
        }
73
74
        $query = SQLUpdate::create()
75
            ->setTable("\"$tableName\"")
76
            ->assignSQL('"Sort"', "\"$tableName\".\"Sort\" $operator 1")
77
            ->addWhere([$filter, "\"$tableName\".\"ParentID\"" => $parentId]);
78
79
        $query->execute();
80
81
        // Now use the ORM to write a new version of the record that we are directly reordering
82
        $element->Sort = $newBlockPosition;
83
        $element->write();
84
85
        return $element;
86
    }
87
}
88