Passed
Push — 4-cactus ( 4faea9...69d03a )
by Paolo
03:39
created

FoldersController::positionToInt()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 1
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2018 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
namespace BEdita\API\Controller;
14
15
use BEdita\Core\Model\Action\ListRelatedFoldersAction;
16
use Cake\Network\Exception\NotFoundException;
17
use Cake\ORM\Association;
18
use Cake\Utility\Hash;
19
20
/**
21
 * Controller for `/folders` endpoint.
22
 *
23
 * The main aim is to bridge `parent` API relationship to `parents` BTM association.
24
 *
25
 * @since 4.0.0
26
 */
27
class FoldersController extends ObjectsController
28
{
29
    /**
30
     * {@inheritDoc}
31
     */
32
    public $modelClass = 'Folders';
33
34
    /**
35
     * {@inheritDoc}
36
     */
37
    protected $_defaultConfig = [
38
        'allowedAssociations' => [
39
            'parent' => ['folders'],
40
            'children' => [],
41
        ],
42
    ];
43
44
    /**
45
     * {@inheritDoc}
46
     *
47
     * `parent` relationship is valid and will return `parents` association.
48
     * `parents` relationship is not allowed.
49
     */
50
    protected function findAssociation($relationship)
51
    {
52
        if ($relationship === 'parents') {
53
            throw new NotFoundException(__d('bedita', 'Relationship "{0}" does not exist', $relationship));
54
        }
55
56
        if ($relationship === 'parent') {
57
            return $this->Table->association('Parents');
58
        }
59
60
        return parent::findAssociation($relationship);
61
    }
62
63
    /**
64
     * {@inheritDoc}
65
     */
66
    protected function getAvailableTypes($relationship)
67
    {
68
        if ($relationship === 'parent') {
69
            return ['folders'];
70
        }
71
        if ($relationship === 'children') {
72
            return ['objects'];
73
        }
74
75
        return parent::getAvailableTypes($relationship);
76
    }
77
78
    /**
79
     * {@inheritDoc}
80
     *
81
     * @return \BEdita\Core\Model\Action\ListRelatedFoldersAction
82
     */
83
    protected function getAssociatedAction(Association $association)
84
    {
85
        return new ListRelatedFoldersAction(compact('association'));
86
    }
87
88
    /**
89
     * {@inheritDoc}
90
     *
91
     * Folder with Parents association allows GET and PATCH
92
     */
93
    protected function setRelationshipsAllowedMethods(Association $association)
94
    {
95
        parent::setRelationshipsAllowedMethods($association);
96
97
        if ($association->getName() === 'Parents') {
98
            $allowedMethods = ['get', 'patch'];
99
            $this->request->allowMethod($allowedMethods);
0 ignored issues
show
Bug introduced by
The method allowMethod() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

99
            $this->request->/** @scrutinizer ignore-call */ 
100
                            allowMethod($allowedMethods);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
100
        }
101
    }
102
103
    /**
104
     * {@inheritDoc}
105
     */
106
    public function relationships()
107
    {
108
        if ($this->request->getParam('relationship') === 'children' && in_array($this->request->getMethod(), ['POST', 'PATCH'])) {
109
            $this->request = $this->request->withParsedBody($this->getDataSortedByPosition());
110
        }
111
112
        return parent::relationships();
113
    }
114
115
    /**
116
     * Sort request data using `meta.relation.position`.
117
     *
118
     *  The order will be:
119
     * - null as first
120
     * - positive desc (i.e. 5, 3, 1)
121
     * - negative desc (i.e. -1, -3, -5)
122
     *
123
     * @return array
124
     */
125
    protected function getDataSortedByPosition()
126
    {
127
        $data = $this->request->getData();
128
129
        usort($data, function ($a, $b) {
130
            $positionA = Hash::get($a, '_meta.relation.position');
131
            $positionB = Hash::get($b, '_meta.relation.position');
132
            if ($positionA === null) {
133
                return -1;
134
            }
135
136
            if ($positionB === null) {
137
                return 1;
138
            }
139
140
            $positionA = $this->positionToInt($positionA);
141
            $positionB = $this->positionToInt($positionB);
142
143
            // if they have the same sign then sort desc
144
            if ($positionA * $positionB > 0) {
145
                return $positionB - $positionA;
146
            }
147
148
            if ($positionA > 0) {
149
                return -1;
150
            }
151
152
            return 1;
153
        });
154
155
        return $data;
156
    }
157
158
    /**
159
     * Given a position as string return its int value.
160
     *
161
     * @param string $position The position to parse as integer.
162
     * @return int
163
     */
164
    protected function positionToInt($position)
165
    {
166
        if ($position === 'first') {
167
            return 1;
168
        }
169
170
        if ($position === 'last') {
171
            return -1;
172
        }
173
174
        return (int)$position;
175
    }
176
}
177