Completed
Push — master ( 190091...7bc446 )
by Russell
9s
created

JSONTextExtension::updateCMSFields()   C

Complexity

Conditions 7
Paths 4

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 15
nc 4
nop 1
1
<?php
2
3
/**
4
 * This {@link DataExtension} allows you to declare arbitrary input fields in
5
 * your getCMSFields() methods without them ever going near an equivalent DBField.
6
 *
7
 * The SilverStripe default gives you one DBField for every input field declared
8
 * in getCMSFields(). This extension however allows you to use a single blob
9
 * of JSON, stored in a single {@link JSONTextField} and manage each key=>value pair
10
 * from individual form input fields, without needing to declare equivalent or further
11
 * database fields. All you need to do is add a `$json_field_map` config static to
12
 * your model (See below).
13
 *
14
 * Notes:
15
 * - Untested on non CHAR DB field-types (v0.8)
16
 * - Only works for single dimensional JSON data
17
 *
18
 * <code>
19
 * private static $db = [
20
 *      'TestJSON' => JSONText::class,
21
 * ];
22
 *
23
 * private static $json_field_map = [
24
 *      'TestJSON' => ['TestField1', 'TestField2']
25
 * ];
26
 *
27
 * public function getCMSFields()
28
 * {
29
 *      $fields = parent::getCMSFields();
30
 *      $fields->addFieldsToTab('Root.Main', [
31
 *          TextField::create('TestField1', 'Test 1'),
32
 *          TextField::create('TestField2', 'Test 2'),
33
 *          TextField::create('TestJSON', 'Some JSON') // Uses a TextField for demo, normally this would be hidden from CMS users
34
 *      ]);
35
 *
36
 *      return $fields;
37
 * }
38
 * </code>
39
 *
40
 * @package jsontext
41
 * @subpackage control
42
 * @author Russell Michell <[email protected]>
43
 */
44
45
namespace PhpTek\JSONText\Extension;
46
47
use PhpTek\JSONText\Exception\JSONTextException;
48
use PhpTek\JSONText\ORM\FieldType\JSONText;
49
use SilverStripe\ORM\DataExtension;
50
use SilverStripe\Control\Controller;
51
use SilverStripe\CMS\Controllers\CMSPageEditController;
52
53
class JSONTextExtension extends DataExtension
54
{
55
    /**
56
     * Pre-process incoming CMS POST data, and modify any available {@link JSONText}
57
     * data for presentation in "headless" input fields.
58
     *
59
     * @return null
60
     */
61
	public function onBeforeWrite()
62
    {
63
        parent::onBeforeWrite();
64
65
        $owner = $this->getOwner();
66
        $controller = Controller::curr();
67
        $postVars = $controller->getRequest()->postVars();
68
        $fieldMap = $owner->config()->get('json_field_map');
69
        $doUpdate = (
70
            count($postVars) &&
71
            !empty($fieldMap) &&
72
            in_array(get_class($controller), [CMSPageEditController::class])
73
        );
74
75
        if (!$doUpdate) {
76
            return null;
77
        }
78
79
        // Could also use DataObject::getSchema()->fieldSpecs()
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
80
        foreach ($owner->config()->get('db') as $field => $type) {
81
            if ($type === JSONText::class) {
82
                $this->updateJSON($postVars, $owner);
83
            }
84
        }
85
    }
86
87
    /**
88
     * Called from {@link $this->onBeforeWrote()}. Inserts or updates each available
89
     * JSONText DB field with the appropriate input-field data, as per the model's
90
     * "json_field_map" config static.
91
     *
92
     * @param  array $postVars
93
     * @param  DataObject $owner
94
     * @return void
95
     * @throws JSONTextException
96
     */
97
    public function updateJSON(array $postVars, $owner)
98
    {
99
        $jsonFieldMap = $owner->config()->get('json_field_map');
100
101
        foreach ($jsonFieldMap as $jsonField => $mappedFields) {
102
            $jsonFieldData = [];
103
104
            foreach ($mappedFields as $fieldName) {
105
                if (!isset($postVars[$fieldName])) {
106
                    $msg = sprintf('%s doesn\'t exist in POST data.', $fieldName);
107
                    throw new JSONTextException($msg);
108
                }
109
110
                $jsonFieldData[$fieldName] = $postVars[$fieldName];
111
            }
112
113
            $fieldValue = singleton(JSONText::class)->toJson($jsonFieldData);
114
            $owner->setField($jsonField, $fieldValue);
115
        }
116
    }
117
118
    /**
119
     * The CMS input fields declared in the json_field_map static, are not DB-backed,
120
     * by virtue of this extension, they are backed by specific values represented
121
     * in the relevant JSON data. Therefore we need to pre-populate each such field's
122
     * value.
123
     *
124
     * @param  FieldList $fields
125
     * @return void
126
     */
127
    public function updateCMSFields(\SilverStripe\Forms\FieldList $fields)
128
    {
129
        $owner = $this->getOwner();
130
        $jsonFieldMap = $owner->config()->get('json_field_map');
131
132
        if (empty($jsonFieldMap)) {
133
            return;
134
        }
135
136
        foreach ($jsonFieldMap as $jsonField => $mappedFields) {
137
            if (!$owner->getField($jsonField)) {
138
                continue;
139
            }
140
141
            $jsonFieldObj = $owner->dbObject($jsonField);
142
143
            foreach ($mappedFields as $fieldName) {
144
                if (!$fieldValue = $jsonFieldObj->query('->>', $fieldName)) {
145
                    continue;
146
                }
147
148
                if ($fieldValue = array_values($jsonFieldObj->toArray($fieldValue))) {
149
                    $fieldValue = $fieldValue[0];
150
                    $owner->setField($fieldName, $fieldValue);
151
                }
152
            }
153
        }
154
    }
155
}
156