Completed
Push — master ( 0d7657...df0666 )
by Russell
07:37
created

JSONTextExtension::updateJSON()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 4
nop 2
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 input fields without needing to declare equivalent or further
11
 * database fields. All you need to do is add a `$json_field_map` 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',
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 JSONText\Extensions;
46
47
use JSONText\Fields\JSONText;
48
use JSONText\Exceptions\JSONTextException;
49
50
class JSONTextExtension extends \DataExtension
51
{    
0 ignored issues
show
Coding Style introduced by
The opening class brace should be on a newline by itself.
Loading history...
52
    /**
53
     * Pre-process incoming CMS POST data, and modify any available {@link JSONText}
54
     * data for presentation in "headless" input fields.
55
     * 
56
     * @return null
57
     */
58
	public function onBeforeWrite()
59
    {
60
        parent::onBeforeWrite();
61
        
62
        $owner = $this->getOwner();
63
        $controller = \Controller::curr();
64
        $postVars = $controller->getRequest()->postVars();
65
        $doUpdate = (
66
            count($postVars) &&
67
            in_array(get_class($controller), ['CMSPageEditController', 'FakeController']) && 
68
            !empty($owner->config()->json_field_map)
69
        );
70
        
71
        if (!$doUpdate) {
72
            return null;
73
        }
74
        
75
        foreach ($owner->db() as $field => $type) {
76
            if ($type === 'JSONText') {
77
                $this->updateJSON($postVars, $owner);
78
            }
79
        }
80
    }
81
    
82
    /**
83
     * Called from {@link $this->onBeforeWrote()}. Inserts or updates each available
84
     * JSONText DB field with the appropriate input-field data, as per the model's 
85
     * "json_field_map" config static.
86
     * 
87
     * @param array $postVars
88
     * @param DataObject $owner
89
     * @return void
90
     * @throws JSONTextException
91
     */
92
    public function updateJSON(array $postVars, $owner)
93
    {
94
        $jsonFieldMap = $owner->config()->json_field_map;
95
        
96
        foreach ($jsonFieldMap as $jsonField => $mappedFields) {
97
            $jsonFieldData = [];
98
            
99
            foreach ($mappedFields as $fieldName) {
100
                if (!isset($postVars[$fieldName])) {
101
                    $msg = sprintf('%s doesn\'t exist in POST data.', $fieldName);
102
                    throw new JSONTextException($msg);
103
                }
104
                
105
                $jsonFieldData[$fieldName] = $postVars[$fieldName];
106
            }
107
            
108
            $fieldValue = singleton('JSONText')->toJson($jsonFieldData);
109
            $owner->setField($jsonField, $fieldValue);
110
        }
111
    }
112
    
113
    /**
114
     * The CMS input fields declared in the json_field_map static, are not DB-backed,
115
     * by virtue of this extension, they are backed by specific values represented
116
     * in the relevant JSON data. Therefore we need to pre-populate each such field's
117
     * value.
118
     * 
119
     * @param FieldList $fields
120
     * @return void
121
     */
122
    public function updateCMSFields(\FieldList $fields)
123
    {
124
        $owner = $this->getOwner();
125
        $jsonFieldMap = $owner->config()->json_field_map;
126
        
127
        foreach ($jsonFieldMap as $jsonField => $mappedFields) {
128
            if (!$owner->getField($jsonField)) {
129
                continue;
130
            }
131
            
132
            $jsonFieldObj = $owner->dbObject($jsonField);
133
            
134
            foreach ($mappedFields as $fieldName) {
135
                if (!$fieldValue = $jsonFieldObj->query('->>', $fieldName)) {
136
                    continue;
137
                }
138
                
139
                if ($fieldValue = array_values($jsonFieldObj->toArray($fieldValue))) {
140
                    $fieldValue = $fieldValue[0];
141
                    $owner->setField($fieldName, $fieldValue);
142
                }
143
            }
144
        }
145
    }
146
}
147