From 3ffc7424793def2a4c1e37ecadd3f4e364f669e7 Mon Sep 17 00:00:00 2001 From: zauberfisch Date: Thu, 21 Sep 2017 11:45:56 +0000 Subject: [PATCH] Nested fields with url_handlers (eg UploadField) now work in DataListField --- _config/extensions.yml | 9 +++++ javascript/ArrayListField.js | 4 +-- src/Form/ArrayListField.php | 39 +++++++++++++++++++-- src/Form/FormExtension.php | 34 +++++++++++++++++++ src/Form/ProxyArrayListField.php | 58 ++++++++++++++++++++++++++++++++ src/Form/UploadField.php | 42 +++++++++++++++++++++++ 6 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 _config/extensions.yml create mode 100644 src/Form/FormExtension.php create mode 100644 src/Form/ProxyArrayListField.php diff --git a/_config/extensions.yml b/_config/extensions.yml new file mode 100644 index 0000000..e6b672d --- /dev/null +++ b/_config/extensions.yml @@ -0,0 +1,9 @@ +--- +Name: silverstripe-serialized-dataobject-extensions +After: 'framework/*','cms/*' +--- +Form: + extensions: + - 'zauberfisch\SerializedDataObject\Form\FormExtension' + url_handlers: + 'field/$FieldName!': 'handleFieldArrayList' diff --git a/javascript/ArrayListField.js b/javascript/ArrayListField.js index 3653870..9008121 100644 --- a/javascript/ArrayListField.js +++ b/javascript/ArrayListField.js @@ -37,10 +37,10 @@ recordList = field.getRecordList(), _this = this, newIndex = recordList.find('.record').length, - url = field.data('add-record-url') + '?index=' + newIndex; + url = field.data('add-record-url'); this.addClass('loading'); this.getRootForm().addClass('changed'); - $.get(url, function (content) { + $.get(url, {'index': newIndex}, function (content) { recordList.append(content); _this.removeClass('loading'); _this.blur(); diff --git a/src/Form/ArrayListField.php b/src/Form/ArrayListField.php index a23aa4c..6a62546 100644 --- a/src/Form/ArrayListField.php +++ b/src/Form/ArrayListField.php @@ -10,6 +10,7 @@ class ArrayListField extends FormField { protected $recordFieldsCallback; + protected $recordFieldsUpdateCallback; protected $recordClassName; protected $orderable = false; @@ -147,6 +148,10 @@ protected function getRecordFields($index, AbstractDataObject $record = null) { ->addExtraClass('controls') ); $this->prefixRecordFields($index, $recordFields); + $callback = $this->getRecordFieldsUpdateCallback(); + if ($callback) { + $recordFields = call_user_func($callback, $recordFields, $this, $record); + } return (new \CompositeField($recordFields))->addExtraClass('record'); } @@ -244,6 +249,20 @@ public function getPrefixedRecordFieldName($index, $fieldName) { return sprintf('%s[%s][%s]', $this->getName(), $index, $fieldName); } + public function handleSubField($fullFieldName) { + $str = substr($fullFieldName, strlen($this->getName())); + if (preg_match('/^\[(\d*)\]/', $str, $matches)) { + $fields = $this->getRecordFields($matches[1]); + $subField = $fields->FieldList()->dataFieldByName($fullFieldName); + if (!$subField) { + $subField = $fields->FieldList()->fieldByName($fullFieldName); + } + $subField->setForm($this->getForm()); + return $subField; + } + return null; + } + /** * @param \DataObjectInterface $record */ @@ -285,7 +304,7 @@ public function setForm($form) { } /** - * @param mixed $recordFieldsCallback + * @param callable $recordFieldsCallback * @return ArrayListField */ public function setRecordFieldsCallback($recordFieldsCallback) { @@ -294,7 +313,7 @@ public function setRecordFieldsCallback($recordFieldsCallback) { } /** - * @return mixed + * @return callable */ public function getRecordFieldsCallback() { $callback = $this->recordFieldsCallback; @@ -314,4 +333,20 @@ public function getRecordFieldsCallback() { } return $callback; } + + /** + * @param callable $recordFieldsUpdateCallback + * @return ArrayListField + */ + public function setRecordFieldsUpdateCallback($recordFieldsUpdateCallback) { + $this->recordFieldsUpdateCallback = $recordFieldsUpdateCallback; + return $this; + } + + /** + * @return callable|null + */ + public function getRecordFieldsUpdateCallback() { + return $this->recordFieldsUpdateCallback; + } } diff --git a/src/Form/FormExtension.php b/src/Form/FormExtension.php new file mode 100644 index 0000000..4c6db9a --- /dev/null +++ b/src/Form/FormExtension.php @@ -0,0 +1,34 @@ + 'handleFieldArrayList', +// ]; + + + /** + * @param \SS_HTTPRequest $request + * @return \FormField + */ + public function handleFieldArrayList($request) { + $field = $this->owner->handleField($request); + if (!$field) { + $fieldName = $request->param('FieldName'); + foreach($this->owner->Fields()->dataFields() as $dataField) { + /** @var \FormField|ArrayListField $dataField */ + if ($dataField->is_a(ArrayListField::class)) { + if (strpos($fieldName, $dataField->getName()) == 0) { + $field = $dataField->handleSubField($fieldName); + break; + } + } + } + } + return $field; + } +} diff --git a/src/Form/ProxyArrayListField.php b/src/Form/ProxyArrayListField.php new file mode 100644 index 0000000..92417aa --- /dev/null +++ b/src/Form/ProxyArrayListField.php @@ -0,0 +1,58 @@ +setRecordFieldsUpdateCallback(function ($fields, $listField, $record = null) use ($_this) { + foreach($fields as $field) { + $_this->push(new ProxyArrayListField_FieldProxy($field)); + } + return $fields; + }), + ]); + $this->setName("{$name}_proxy_holder"); + } + + +} + +class ProxyArrayListField_FieldProxy extends \DatalessField { + private static $allowed_actions = [ + 'handleField', + ]; + private static $url_handlers = [ + '' => 'handleField', + ]; + protected $originalField; + + /** + * @param \FormField $originalField + */ + public function __construct($originalField) { + $this->originalField = $originalField; + parent::__construct($originalField->getName()); + } + + + public function handleField(\SS_HTTPRequest $request) { + return $this->originalField; + } + + public function Field($properties = []) { + return ''; + } + + public function FieldHolder($properties = []) { + return ''; + } + + public function SmallFieldHolder($properties = []) { + return ''; + } +} diff --git a/src/Form/UploadField.php b/src/Form/UploadField.php index 7c1fce9..a0a1e9a 100644 --- a/src/Form/UploadField.php +++ b/src/Form/UploadField.php @@ -2,6 +2,7 @@ namespace zauberfisch\SerializedDataObject\Form; +use SS_HTTPRequest; use zauberfisch\SerializedDataObject\DataList; use zauberfisch\SerializedDataObject\DBField\DataListField; @@ -46,4 +47,45 @@ public function setValue($value, $record = null) { } return parent::setValue($value, $record); } + + private static $allowed_actions = [ + 'upload', + ]; + + public function upload(SS_HTTPRequest $request) { + $fieldName = $this->getName(); + $baseStrLength = strpos($fieldName, '['); + if ($baseStrLength) { + $postVars = $request->postVars(); + $baseName = substr($fieldName, 0, $baseStrLength); + if (isset($postVars[$baseName])) { + $postVars[$fieldName] = $this->flattenFilesArray($postVars[$baseName]); + $request = new SS_HTTPRequest( + $request->httpMethod(), + $request->getURL(), + $request->getVars(), + $postVars + ); + } + } + $return = parent::upload($request); + return $return; + } + + protected function flattenFilesArray($array) { + $fieldName = $this->getName(); + $keys = substr($fieldName, strpos($fieldName, '[')); + $keys = trim($keys, '['); + $keys = trim($keys, ']'); + $keys = explode('][', $keys); + $return = []; + foreach (['name', 'type', 'tmp_name', 'error', 'size'] as $field) { + $data = $array[$field]; + foreach ($keys as $key) { + $data = $data[$key]; + } + $return[$field] = $data; + } + return $return; + } }