Skip to content

Commit 8fddc5b

Browse files
committed
implemented nested forms
1 parent 42951fc commit 8fddc5b

File tree

3 files changed

+236
-0
lines changed

3 files changed

+236
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace wcf\system\form\builder;
4+
5+
class NestedFormDocument extends FormDocument {
6+
/**
7+
* @inheritDoc
8+
*/
9+
public function getRequestData($index = null) {
10+
if ($this->requestData === null) {
11+
$this->requestData = $_POST;
12+
}
13+
14+
if ($index !== null && strpos($index, '[') !== false) {
15+
preg_match('/^([^\[]+)(\[.*\])$/', $index, $matches);
16+
if (!empty($matches[2])) {
17+
unset($matches[0]);
18+
19+
preg_match_all('/(?:\[([^\]]+)\])/', $matches[2], $parts);
20+
if (!empty($parts[1])) {
21+
$i = 0;
22+
$source = $this->requestData[$matches[1]];
23+
while (!empty($parts[1][$i]) && is_array($source)) {
24+
$source = $source[$parts[1][$i]] ?? null;
25+
$i++;
26+
}
27+
28+
if ($source !== null) {
29+
return $source;
30+
}
31+
}
32+
}
33+
}
34+
35+
return parent::getRequestData($index);
36+
}
37+
38+
/**
39+
* @inheritDoc
40+
*/
41+
public function hasRequestData($index = null) {
42+
$requestData = $this->getRequestData();
43+
44+
if ($index !== null && strpos($index, '[') !== false) {
45+
preg_match('/^([^\[]+)(\[.*\])$/', $index, $matches);
46+
if (!empty($matches[2])) {
47+
unset($matches[0]);
48+
49+
preg_match_all('/(?:\[([^\]]+)\])/', $matches[2], $parts);
50+
if (!empty($parts[1])) {
51+
$i = 0;
52+
$source = $requestData[$matches[1]];
53+
while (!empty($parts[1][$i]) && is_array($source)) {
54+
$source = $source[$parts[1][$i]] ?? null;
55+
$i++;
56+
}
57+
58+
return $source !== null;
59+
}
60+
}
61+
}
62+
63+
return parent::hasRequestData($index);
64+
}
65+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace wcf\system\form\builder\container;
4+
5+
use wcf\system\WCF;
6+
7+
class DummyFormContainer extends FormContainer {
8+
/**
9+
* @inheritDoc
10+
*/
11+
public function __construct() {}
12+
13+
/**
14+
* @inheritDoc
15+
*/
16+
public function getHtml() {
17+
return WCF::getTPL()->fetch('__formContainerChildren', 'wcf', array_merge($this->getHtmlVariables(), [
18+
'container' => $this
19+
]), true);
20+
}
21+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<?php
2+
3+
namespace wcf\system\form\builder\data\processor;
4+
5+
use wcf\data\IStorableObject;
6+
use wcf\system\form\builder\container\DummyFormContainer;
7+
use wcf\system\form\builder\container\IFormContainer;
8+
use wcf\system\form\builder\field\IFormField;
9+
use wcf\system\form\builder\IFormDocument;
10+
use wcf\system\form\builder\IFormNode;
11+
12+
class PrefixedFormDataProcessor extends AbstractFormDataProcessor {
13+
/**
14+
* processor id primarily used for error messages
15+
* @var string
16+
*/
17+
protected $id;
18+
19+
/**
20+
* @var string
21+
*/
22+
protected $wrapperProperty;
23+
24+
/**
25+
* @var string
26+
*/
27+
protected $targetProperty;
28+
29+
/**
30+
* Initializes a new PrefixedFormDataProcessor object.
31+
*
32+
* @param string $id processor id primarily used for error messages, does not have to be unique
33+
* @param string $wrapperProperty
34+
* @param string $targetProperty
35+
*
36+
* @throws \InvalidArgumentException if either id or processor callable are invalid
37+
*/
38+
public function __construct($id, $wrapperProperty, $targetProperty = '') {
39+
if (preg_match('~^[a-z][A-z0-9-]*$~', $id) !== 1) {
40+
throw new \InvalidArgumentException("Invalid id '{$id}' given.");
41+
}
42+
43+
$this->id = $id;
44+
$this->wrapperProperty = $wrapperProperty;
45+
$this->targetProperty = $targetProperty;
46+
}
47+
48+
/**
49+
* @inheritDoc
50+
*/
51+
public function processFormData(IFormDocument $document, array $parameters) {
52+
/** @var DummyFormContainer $container */
53+
$container = $document->getNodeById($this->id);
54+
if ($container === null || !$container->hasChildren()) {
55+
return $parameters;
56+
}
57+
58+
$this->processNode($container, $parameters);
59+
60+
return $parameters;
61+
}
62+
63+
/**
64+
* @param IFormNode $node
65+
* @param mixed[] $parameters
66+
*/
67+
protected function processNode(IFormNode $node, &$parameters) {
68+
if ($node instanceof IFormContainer) {
69+
foreach ($node->children() as $childNode) {
70+
$this->processNode($childNode, $parameters);
71+
}
72+
}
73+
else if ($node instanceof IFormField) {
74+
$id = $node->getPrefixedId();
75+
76+
if (preg_match('/^([^\[\]]+)((?:\[[^\]]+\]){1,})$/', $id, $matches)) {
77+
unset($parameters['data'][$id]);
78+
79+
$property = '$parameters[\'data\'][\'' . $matches[1] . '\']' . str_replace(['[', ']'], ['[\'', '\']'], $matches[2]);
80+
$value = $node->getSaveValue();
81+
$test = $property . '=$value;';
82+
eval($test);
83+
}
84+
}
85+
}
86+
87+
/**
88+
* @inheritDoc
89+
*/
90+
public function processObjectData(IFormDocument $document, array $data, IStorableObject $object) {
91+
/** @var DummyFormContainer $container */
92+
$container = $document->getNodeById($this->id);
93+
94+
$container = $document->getNodeById($this->id);
95+
if ($container === null || !$container->hasChildren()) {
96+
return $data;
97+
}
98+
99+
$this->processNodeObject($container, $data);
100+
unset($data[$container->getPrefixedId()]);
101+
102+
return $data;
103+
}
104+
105+
/**
106+
* @param IFormNode $node
107+
* @param mixed[] $data
108+
*/
109+
protected function processNodeObject(IFormNode $node, &$data) {
110+
if ($node instanceof IFormContainer) {
111+
foreach ($node->children() as $childNode) {
112+
$this->processNodeObject($childNode, $data);
113+
}
114+
}
115+
else if ($node instanceof IFormField) {
116+
$id = $node->getPrefixedId();
117+
118+
if (preg_match('/^([^\[\]]+)((?:\[[^\]]+\]){1,})$/', $id, $matches)) {
119+
$data[$id] = $this->getDataFromArray($data, $id);
120+
}
121+
}
122+
}
123+
124+
/**
125+
* @param mixed[] $data
126+
* @param string $index
127+
* @return mixed|null
128+
*/
129+
protected function getDataFromArray($data, $index) {
130+
preg_match('/^([^\[]+)(\[.*\])$/', $index, $matches);
131+
if (!empty($matches[2])) {
132+
unset($matches[0]);
133+
134+
preg_match_all('/(?:\[([^\]]+)\])/', $matches[2], $parts);
135+
if (!empty($parts[1])) {
136+
$i = 0;
137+
$source = $data[$matches[1]];
138+
if (!is_array($source)) $source = unserialize($source);
139+
while (!empty($parts[1][$i]) && is_array($source)) {
140+
$source = $source[$parts[1][$i]] ?? null;
141+
$i++;
142+
}
143+
144+
return $source;
145+
}
146+
}
147+
148+
return null;
149+
}
150+
}

0 commit comments

Comments
 (0)