Skip to content

Commit 2f8f944

Browse files
committed
initial commit
0 parents  commit 2f8f944

File tree

9 files changed

+408
-0
lines changed

9 files changed

+408
-0
lines changed

.editorconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# For more information about the properties used in this file,
2+
# please see the EditorConfig documentation:
3+
# http://editorconfig.org
4+
5+
[*]
6+
charset = utf-8
7+
end_of_line = lf
8+
indent_size = 4
9+
indent_style = space
10+
insert_final_newline = true
11+
trim_trailing_whitespace = true
12+
13+
[{*.yml,package.json,*.js,*.scss}]
14+
indent_size = 2
15+
16+
# The indent size used in the package.json file cannot be changed:
17+
# https://github.com/npm/npm/pull/3180#issuecomment-16336516

LICENCE.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2018, Fullscreen Interactive Limited
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
* Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
11+
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
* Neither the name of the copyright holder nor the names of its
17+
contributors may be used to endorse or promote products derived from
18+
this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# SilverStripe Key Value Field
2+
3+
[![Version](http://img.shields.io/packagist/v/fullscreeninteractive/silverstripe-keyvaluefield.svg)](https://packagist.org/packages/fullscreeninteractive/silverstripe-keyvaluefield)
4+
[![License](http://img.shields.io/packagist/l/fullscreeninteractive/silverstripe-keyvaluefield.svg)](license.md)
5+
6+
A reusable approach to a form field which extends a simple Text field to have
7+
several named parts (keys). This module also supports User Defined Forms.
8+
9+
## Installation
10+
11+
```
12+
composer require fullscreeninteractive/silverstripe-keyvaluefield
13+
```
14+
15+
## Usage
16+
17+
![Image of Function](https://raw.githubusercontent.com/fullscreeninteractive/silverstripe-keyvaluefield/master/client/img/demo.png)
18+
19+
```php
20+
use FullscreenInteractive\KeyValueField\KeyValueField;
21+
22+
$fields = new FieldList(
23+
KeyValueField::create('Quantity', 'Enter quantity of each size')
24+
->setKeys([
25+
'Small',
26+
'Medium',
27+
'Large'
28+
])
29+
);
30+
```
31+
32+
When using ORM managed forms and models (i.e `saveInto`) data will be saved as
33+
a serialized array of the values to each of the keys. You can change this
34+
behaviour if needed in your `Form` class.
35+
36+
```php
37+
public function doSave($data, $form)
38+
{
39+
$quantity = $form->dataFieldByName('Quantity');
40+
41+
// returns an array of key => value
42+
$values = json_decode($quantity->dataValue(), true);
43+
44+
echo $values['Small']
45+
}
46+
```
47+
48+
## Licence
49+
50+
BSD 3-Clause License

_config/.gitkeep

Whitespace-only changes.

client/img/demo.png

35.8 KB
Loading

composer.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "fullscreeninteractive/silverstripe-keyvaluefield",
3+
"description": "A Silverstripe FormField for extending TextField with several parts (keys)",
4+
"type": "silverstripe-vendormodule",
5+
"homepage": "http://silverstripe.org",
6+
"license": "BSD-3-Clause",
7+
"keywords": [
8+
"silverstripe",
9+
"versioned"
10+
],
11+
"authors": [{
12+
"name": "Will Rossiter",
13+
"homepage": "http://www.fullscreen.io"
14+
}],
15+
"require": {
16+
"silverstripe/framework": "^4",
17+
"silverstripe/vendor-plugin": "^1"
18+
},
19+
"require-dev": {
20+
"phpunit/phpunit": "^5.7"
21+
},
22+
"autoload": {
23+
"psr-4": {
24+
"FullscreenInteractive\\KeyValueField\\": "src/",
25+
"FullscreenInteractive\\KeyValueField\\Tests\\": "tests/php/"
26+
}
27+
},
28+
"scripts": {
29+
30+
},
31+
"extra": {
32+
"expose": [
33+
"client"
34+
]
35+
},
36+
"minimum-stability": "dev",
37+
"prefer-stable": true
38+
}

src/EditableKeyValueField.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace FullscreenInteractive\KeyValueField;
4+
5+
use SilverStripe\Forms\FieldList;
6+
use SilverStripe\Forms\TextareaField;
7+
use SilverStripe\UserForms\Model\EditableFormField;
8+
9+
if (class_exists(EditableFormField::class)) {
10+
return;
11+
}
12+
13+
class EditableKeyValueField extends EditableFormField
14+
{
15+
private static $singular_name = 'Key Value Field';
16+
17+
private static $plural_name = 'Key Value Fields';
18+
19+
private static $db = [
20+
'Keys' => 'Text'
21+
];
22+
23+
private static $table_name = 'EditableKeyValueField';
24+
25+
/**
26+
* @return FieldList
27+
*/
28+
public function getCMSFields()
29+
{
30+
$this->beforeUpdateCMSFields(function (FieldList $fields) {
31+
$fields->addFieldsToTab('Root.Main', TextareaField::create('Keys')->setDescription('One key per line'));
32+
});
33+
34+
return parent::getCMSFields();
35+
}
36+
37+
38+
public function getFormField()
39+
{
40+
$field = KeyValueField::create($this->Name, $this->Title ?: false)
41+
->setKeys($this->getKeysAsArray());
42+
43+
$this->doUpdateFormField($field);
44+
45+
return $field;
46+
}
47+
48+
49+
public function getValueFromData($data)
50+
{
51+
$incoming = isset($data[$this->Name]) ? $data[$this->Name] : false;
52+
53+
if (!$incoming) {
54+
return json_encode([]);
55+
}
56+
57+
$value = [];
58+
59+
foreach ($this->getKeysAsArray() as $i => $k) {
60+
if (isset($data[$i])) {
61+
$value[$k] = $data[$i];
62+
}
63+
}
64+
65+
return json_encode($value);
66+
}
67+
68+
69+
public function getKeysAsArray()
70+
{
71+
return array_map(function($k) {
72+
return trim($k);
73+
}, explode(PHP_EOL, $this->Keys));
74+
}
75+
}

src/KeyValueField.php

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
3+
namespace FullscreenInteractive\KeyValueField;
4+
5+
use SilverStripe\Forms\CompositeField;
6+
use SilverStripe\Forms\FieldList;
7+
use SilverStripe\Forms\LabelField;
8+
use SilverStripe\Forms\TextField;
9+
use SilverStripe\ORM\DataObjectInterface;
10+
11+
class KeyValueField extends CompositeField
12+
{
13+
/**
14+
* @var string[]
15+
*/
16+
protected $keys = 0;
17+
18+
19+
public function __construct($name, $title = null, $value = null)
20+
{
21+
$this->setName($name);
22+
$this->setTitle($title);
23+
24+
if ($value) {
25+
$this->setValue($value);
26+
}
27+
}
28+
29+
public function setKeys(array $keys)
30+
{
31+
$this->keys = $keys;
32+
$this->buildChildren();
33+
34+
return $this;
35+
}
36+
37+
38+
public function buildChildren()
39+
{
40+
$children = new FieldList();
41+
42+
$name = $this->name;
43+
$children->push(LabelField::create($this->name . '__label', $this->title)->addExtraClass('left key__label'));
44+
45+
if ($this->keys) {
46+
foreach ($this->keys as $i => $key) {
47+
$fieldName = sprintf("%s[%s]", $name, $i);
48+
$value = isset($this->value[$i]) ? $this->value[$i] : '';
49+
50+
$field = TextField::create($fieldName, $key, $value)
51+
->addExtraClass('key__value');
52+
$this->invokeWithExtensions('updateKeyValueField', $field, $key, $i);
53+
54+
$children->push($field);
55+
}
56+
}
57+
58+
59+
$this->setChildren($children);
60+
61+
return $this;
62+
}
63+
64+
65+
public function saveInto(DataObjectInterface $record)
66+
{
67+
if ($record->hasMethod('set{$this->name}')) {
68+
$record->{'set' . $this->name}($this->dataValue());
69+
} else {
70+
$record->{$this->name} = $this->dataValue();
71+
}
72+
}
73+
74+
75+
/**
76+
* Returns the value of the field as a string. If needing the value as an
77+
* array, use {@link getValue()}.
78+
*
79+
* The main difference between this and {@link getValue()} is that this
80+
* method includes the title of the keys, getValue returns the zero indexed
81+
* values.
82+
*/
83+
public function dataValue()
84+
{
85+
if ($this->value && is_array($this->value)) {
86+
$output = [];
87+
88+
foreach ($this->keys as $i => $key) {
89+
if (isset($this->value[$i])) {
90+
$output[$key] = $this->value[$i];
91+
}
92+
}
93+
}
94+
95+
return json_encode($output);
96+
}
97+
98+
99+
/**
100+
* Set value of this field.
101+
*
102+
* Handles either value as a string (for instance loading from the database)
103+
* or as an array. The array can either be a simple key/value array, where
104+
* the key is hash or name of the field
105+
*/
106+
public function setValue($value, $data = null)
107+
{
108+
if ($value) {
109+
if (is_string($value)) {
110+
$value = json_decode($value, true);
111+
}
112+
113+
if (is_array($value)) {
114+
$first = array_key_first($value);
115+
116+
if (is_string($first)) {
117+
$this->value = [];
118+
119+
foreach ($value as $k => $v) {
120+
$i = array_search($k, $this->keys);
121+
122+
$this->value[$i] = $v;
123+
}
124+
} else {
125+
$this->value = [];
126+
127+
foreach ($value as $key => $val) {
128+
$this->value[$key] = $val;
129+
}
130+
}
131+
} else {
132+
$this->value = [];
133+
}
134+
} else {
135+
$this->value = [];
136+
}
137+
138+
foreach ($this->children as $i => $field) {
139+
if ($field instanceof LabelField) {
140+
continue;
141+
}
142+
143+
$vK = $i - 1;
144+
$v = isset($this->value[$vK]) ? $this->value[$vK] : '';
145+
146+
$field->setValue($v, $data);
147+
}
148+
149+
return $this;
150+
}
151+
152+
153+
public function collateDataFields(&$list, $saveableOnly = false)
154+
{
155+
$list[$this->name] = $this;
156+
}
157+
158+
159+
public function hasData()
160+
{
161+
return true;
162+
}
163+
}

0 commit comments

Comments
 (0)