Passed
Push — master ( e6b7ee...40e526 )
by
unknown
03:49
created

src/Controllers/ElementalAreaController.php (1 issue)

1
<?php
2
3
namespace DNADesign\Elemental\Controllers;
4
5
use DNADesign\Elemental\Forms\EditFormFactory;
6
use DNADesign\Elemental\Models\BaseElement;
7
use Exception;
8
use Psr\Log\LoggerInterface;
9
use SilverStripe\CMS\Controllers\CMSMain;
10
use SilverStripe\Control\HTTPRequest;
11
use SilverStripe\Control\HTTPResponse;
12
use SilverStripe\Control\HTTPResponse_Exception;
13
use SilverStripe\Core\Convert;
14
use SilverStripe\Core\Injector\Injector;
15
use SilverStripe\Forms\Form;
16
use SilverStripe\Security\SecurityToken;
17
18
/**
19
 * Controller for "ElementalArea" - handles loading and saving of in-line edit forms in an elemental area in admin
20
 */
21
class ElementalAreaController extends CMSMain
22
{
23
    const FORM_NAME_TEMPLATE = 'ElementForm_%s';
24
25
    private static $url_segment = 'elemental-area';
26
27
    private static $ignore_menuitem = true;
28
29
    private static $url_handlers = [
30
        // API access points with structured data
31
        'POST api/saveForm/$ID' => 'apiSaveForm',
32
    ];
33
34
    private static $allowed_actions = [
0 ignored issues
show
The private property $allowed_actions is not used, and could be removed.
Loading history...
35
        'elementForm',
36
        'schema',
37
        'apiSaveForm',
38
    ];
39
40
    public function getClientConfig()
41
    {
42
        $clientConfig = parent::getClientConfig();
43
        $clientConfig['form']['elementForm'] = [
44
            'schemaUrl' => $this->Link('schema/elementForm'),
45
            'saveUrl' => $this->Link('api/saveForm'),
46
            'saveMethod' => 'post',
47
            'payloadFormat' => 'json',
48
            'formNameTemplate' => sprintf(static::FORM_NAME_TEMPLATE, '{id}'),
49
        ];
50
        return $clientConfig;
51
    }
52
53
    /**
54
     * @param HTTPRequest|null $request
55
     * @return Form
56
     * @throws HTTPResponse_Exception
57
     */
58
    public function elementForm(HTTPRequest $request = null)
59
    {
60
        // Get ID either from posted back value, or url parameter
61
        if (!$request) {
62
            $this->jsonError(400);
63
            return null;
64
        }
65
        $id = $request->param('ID');
66
        if (!$id) {
67
            $this->jsonError(400);
68
            return null;
69
        }
70
        return $this->getElementForm($id) ?: $this->jsonError(404);
71
    }
72
73
    /**
74
     * @param int $elementID
75
     * @return Form|null Returns null if no element exists for the given ID
76
     */
77
    public function getElementForm($elementID)
78
    {
79
        $scaffolder = Injector::inst()->get(EditFormFactory::class);
80
        $element = BaseElement::get()->byID($elementID);
81
82
        if (!$element) {
83
            return null;
84
        }
85
86
        /** @var Form $form */
87
        $form = $scaffolder->getForm(
88
            $this,
89
            sprintf(static::FORM_NAME_TEMPLATE, $elementID),
90
            ['Record' => $element]
91
        );
92
93
        if (!$element->canEdit()) {
94
            $form->makeReadonly();
95
        }
96
97
        return $form;
98
    }
99
100
    /**
101
     * Save an inline edit form for a block
102
     *
103
     * @param HTTPRequest $request
104
     * @return HTTPResponse|null JSON encoded string or null if an exception is thrown
105
     * @throws HTTPResponse_Exception
106
     */
107
    public function apiSaveForm(HTTPRequest $request)
108
    {
109
        // Validate required input data
110
        if (!isset($this->urlParams['ID'])) {
111
            $this->jsonError(400);
112
            return null;
113
        }
114
115
        $data = Convert::json2array($request->getBody());
116
        if (empty($data)) {
117
            $this->jsonError(400);
118
            return null;
119
        }
120
121
        // Inject request body as request vars
122
        foreach ($data as $key => $value) {
123
            $request->offsetSet($key, $value);
124
        }
125
126
        // Check security token
127
        if (!SecurityToken::inst()->checkRequest($request)) {
128
            $this->jsonError(400);
129
            return null;
130
        }
131
132
        /** @var BaseElement $element */
133
        $element = BaseElement::get()->byID($this->urlParams['ID']);
134
        // Ensure the element can be edited by the current user
135
        if (!$element || !$element->canEdit()) {
136
            $this->jsonError(403);
137
            return null;
138
        }
139
140
        // Remove the pseudo namespaces that were added by the form factory
141
        $data = $this->removeNamespacesFromFields($data, $element->ID);
142
143
        try {
144
            $updated = false;
145
            $element->update($data);
146
            // Check if anything will actually be changed before writing
147
            if ($element->isChanged()) {
148
                $element->write();
149
                // Track changes so we can return to the client
150
                $updated = true;
151
            }
152
        } catch (Exception $ex) {
153
            Injector::inst()->get(LoggerInterface::class)->debug($ex->getMessage());
154
155
            $this->jsonError(500);
156
            return null;
157
        }
158
159
        $body = Convert::raw2json([
160
            'status' => 'success',
161
            'updated' => $updated,
162
        ]);
163
        return HTTPResponse::create($body)->addHeader('Content-Type', 'application/json');
164
    }
165
166
    /**
167
     * Remove the pseudo namespaces that were added to form fields by the form factory
168
     *
169
     * @param array $data
170
     * @param int $elementID
171
     * @return array
172
     */
173
    protected function removeNamespacesFromFields(array $data, $elementID)
174
    {
175
        $output = [];
176
        $template = sprintf(EditFormFactory::FIELD_NAMESPACE_TEMPLATE, $elementID, '');
177
        foreach ($data as $key => $value) {
178
            // Only look at fields that match the namespace template
179
            if (substr($key, 0, strlen($template)) !== $template) {
180
                continue;
181
            }
182
183
            $fieldName = substr($key, strlen($template));
184
            $output[$fieldName] = $value;
185
        }
186
        return $output;
187
    }
188
}
189