Completed
Push — master ( 600451...ae1e12 )
by
unknown
13s
created

ReorderElements::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 12
rs 10
c 0
b 0
f 0
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
15
     */
16
    protected $element;
17
18
    /**
19
     * Create reordering service for specified Element
20
     *
21
     * @param BaseElement $element
22
     */
23
    public function __construct(BaseElement $element)
24
    {
25
        if (!is_subclass_of($element, BaseElement::class)) {
26
            throw new InvalidArgumentException(sprintf(
27
                'Invalid %s passed to %s, got class %s instead',
28
                BaseElement::class,
29
                __CLASS__,
30
                get_class($element)
31
            ));
32
        }
33
34
        $this->setElement($element);
35
    }
36
37
    /**
38
     * Get the Element reordering will be performed on
39
     *
40
     * @return BaseElement
41
     */
42
    public function getElement()
43
    {
44
        return $this->element;
45
    }
46
47
    /**
48
     * Set the Element instance to perform reordering on
49
     *
50
     * @param BaseElement $element
51
     * @return $this
52
     */
53
    public function setElement(BaseElement $element)
54
    {
55
        $this->element = $element;
56
        return $this;
57
    }
58
59
    /**
60
     * Set the ordering of Elements in relation to sibling Elements in the parent {@see ElementalArea}
61
     *
62
     * @param int $elementToBeAfterID ID of the Element to be ordered after
63
     */
64
    public function reorder($elementToBeAfterID = 0)
65
    {
66
        $element = $this->element;
67
        $parentId = $element->ParentID;
0 ignored issues
show
Bug Best Practice introduced by Dylan Wagstaff
The property ParentID does not exist on DNADesign\Elemental\Models\BaseElement. Since you implemented __get, consider adding a @property annotation.
Loading history...
68
        $currentPosition = (int) $element->Sort;
69
        $sortAfterPosition = 0;
70
71
        if ($elementToBeAfterID) {
72
            /** @var BaseElement $afterBlock */
73
            $afterElement = BaseElement::get()->byID($elementToBeAfterID);
74
75
            if (!$afterElement) {
0 ignored issues
show
introduced by Dylan Wagstaff
$afterElement is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
76
                throw new InvalidArgumentException(sprintf(
77
                    '%s#%s not found',
78
                    BaseElement::class,
79
                    $elementToBeAfterID
80
                ));
81
            }
82
83
            // Must be weak comparison as sometimes integers are returned from the DB as strings
84
            if ($afterElement->ParentID != $parentId) {
85
                throw new InvalidArgumentException(
86
                    'Trying to sort element to be placed after an element from a different elemental area'
87
                );
88
            }
89
90
            $sortAfterPosition = (int) $afterElement->Sort;
91
        }
92
93
        // We are updating records with SQL queries to avoid the ORM triggering the creation of new versions
94
        // for each element that is affected by this reordering.
95
        $tableName = Convert::raw2sql(DataObject::getSchema()->tableName(BaseElement::class));
96
97
        if ($sortAfterPosition < $currentPosition) {
98
            $operator = '+';
99
            $filter = "\"$tableName\".\"Sort\" > $sortAfterPosition AND \"$tableName\".\"Sort\" < $currentPosition";
100
            $newBlockPosition = $sortAfterPosition + 1;
101
        } else {
102
            $operator = '-';
103
            $filter = "\"$tableName\".\"Sort\" <= $sortAfterPosition AND \"$tableName\".\"Sort\" > $currentPosition";
104
            $newBlockPosition = $sortAfterPosition;
105
        }
106
107
        $query = SQLUpdate::create()
108
            ->setTable("\"$tableName\"")
109
            ->assignSQL('"Sort"', "\"$tableName\".\"Sort\" $operator 1")
110
            ->addWhere([$filter, "\"$tableName\".\"ParentID\"" => $parentId]);
111
112
        $query->execute();
113
114
        // Now use the ORM to write a new version of the record that we are directly reordering
115
        $element->Sort = $newBlockPosition;
116
        $element->write();
117
118
        return $element;
119
    }
120
}
121