chg: [component:CRUD] Support of validation and re-edition (WiP)
parent
b11db037d7
commit
94fbd74918
|
@ -134,7 +134,7 @@ class CRUDComponent extends Component
|
|||
});
|
||||
$metaTemplates = $metaQuery->all();
|
||||
}
|
||||
$this->Controller->set('metaTemplates', $metaTemplates);
|
||||
// $this->Controller->set('metaTemplates', $metaTemplates->toArray());
|
||||
return $metaTemplates;
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,11 @@ class CRUDComponent extends Component
|
|||
foreach ($data->getErrors() as $field => $errorData) {
|
||||
$errorMessages = [];
|
||||
foreach ($errorData as $key => $value) {
|
||||
$errorMessages[] = $value;
|
||||
if (is_array($value)) {
|
||||
$errorMessages[] = implode('& ', Hash::extract($value, "{s}.{s}"));
|
||||
} else {
|
||||
$errorMessages[] = $value;
|
||||
}
|
||||
}
|
||||
$validationMessage .= __('{0}: {1}', $field, implode(',', $errorMessages));
|
||||
}
|
||||
|
@ -281,28 +285,50 @@ class CRUDComponent extends Component
|
|||
'uuid' => Text::uuid(),
|
||||
]);
|
||||
$entity->meta_fields[] = $metaField;
|
||||
$entity->MetaTemplates[$template_id]->meta_template_fields[$meta_template_field_id]->metaFields[] = $metaField;
|
||||
// $entity->MetaTemplates[$template_id]->meta_template_fields[$meta_template_field_id]->metaFields['new'][] = $metaField;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$new_value = $meta_field['value'];
|
||||
$index = $metaFieldsIndex[$meta_field_id];
|
||||
if (!empty($new_value)) {
|
||||
// update meta_field
|
||||
$metaFieldsTable->patchEntity($entity->meta_fields[$index], [
|
||||
'value' => $new_value,
|
||||
]);
|
||||
// update meta_field and attach validation errors
|
||||
if (!empty($metaFieldsIndex[$meta_field_id])) {
|
||||
$index = $metaFieldsIndex[$meta_field_id];
|
||||
$metaFieldsTable->patchEntity($entity->meta_fields[$index], [
|
||||
'value' => $new_value, 'meta_template_field_id' => $rawMetaTemplateField->id
|
||||
], ['value']);
|
||||
$metaFieldsTable->patchEntity(
|
||||
$entity->MetaTemplates[$template_id]->meta_template_fields[$meta_template_field_id]->metaFields[$meta_field_id],
|
||||
['value' => $new_value, 'meta_template_field_id' => $rawMetaTemplateField->id],
|
||||
['value']
|
||||
);
|
||||
} else { // metafield comes from a second post where the temporary entity has already been created
|
||||
$metaField = $metaFieldsTable->newEmptyEntity();
|
||||
$metaFieldsTable->patchEntity($metaField, [
|
||||
'value' => $new_value,
|
||||
'scope' => $this->Table->metaFields, // get scope from behavior
|
||||
'field' => $rawMetaTemplateField->field,
|
||||
'meta_template_id' => $rawMetaTemplateField->meta_template_id,
|
||||
'meta_template_field_id' => $rawMetaTemplateField->id,
|
||||
'parent_id' => $entity->id,
|
||||
'uuid' => Text::uuid(),
|
||||
]);
|
||||
$entity->meta_fields[] = $metaField;
|
||||
$entity->MetaTemplates[$template_id]->meta_template_fields[$meta_template_field_id]->metaFields[] = $metaField;
|
||||
}
|
||||
} else {
|
||||
// remove meta field - Just checking if not having it will have it deleted or if it should actually be deleted
|
||||
// Maybe Table->unlink ?
|
||||
// Metafield value is empty, indicating the field should be removed
|
||||
$index = $metaFieldsIndex[$meta_field_id];
|
||||
$metaFieldsToDelete[] = $entity->meta_fields[$index];
|
||||
unset($entity->meta_fields[$index]);
|
||||
unset($entity->MetaTemplates[$template_id]->meta_template_fields[$meta_template_field_id]->metaFields[$meta_field_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// $input['metaFields'] = $metaFields;
|
||||
$entity->setDirty('meta_fields', true);
|
||||
return ['entity' => $entity, 'metafields_to_delete' => $metaFieldsToDelete];
|
||||
}
|
||||
|
@ -348,7 +374,6 @@ class CRUDComponent extends Component
|
|||
}
|
||||
$data = $this->Table->get($id, $getParam);
|
||||
$data = $this->attachMetaTemplates($data, $metaTemplates->toArray());
|
||||
// $data = $this->getMetaFields($id, $data);
|
||||
if (!empty($params['fields'])) {
|
||||
$this->Controller->set('fields', $params['fields']);
|
||||
}
|
||||
|
@ -360,10 +385,11 @@ class CRUDComponent extends Component
|
|||
if (!empty($params['fields'])) {
|
||||
$patchEntityParams['fields'] = $params['fields'];
|
||||
}
|
||||
$massagedData = $this->massageMetaFields($data, $input, $metaTemplates);
|
||||
unset($input['MetaTemplates']); // Avoid MetaTemplates to be overriden when patching entity
|
||||
$data = $massagedData['entity'];
|
||||
$metaFieldsToDelete = $massagedData['metafields_to_delete'];
|
||||
$data = $this->Table->patchEntity($data, $input, $patchEntityParams);
|
||||
$massaged = $this->massageMetaFields($data, $input, $metaTemplates);
|
||||
$data = $massaged['entity'];
|
||||
$metaFieldsToDelete = $massaged['metafields_to_delete'];
|
||||
if (isset($params['beforeSave'])) {
|
||||
$data = $params['beforeSave']($data);
|
||||
}
|
||||
|
@ -389,8 +415,10 @@ class CRUDComponent extends Component
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// debug($data['MetaTemplates']);
|
||||
$validationErrors = $data->getErrors();
|
||||
$validationMessage = $this->prepareValidationMessage($validationErrors);
|
||||
// $validationMessage = $this->prepareValidationMessage($validationErrors);
|
||||
$validationMessage = $this->prepareValidationError($data);
|
||||
$message = __(
|
||||
'{0} could not be modified.{1}',
|
||||
$this->ObjectAlias,
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Model\Table;
|
|||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
use Cake\ORM\RulesChecker;
|
||||
|
||||
class MetaFieldsTable extends AppTable
|
||||
{
|
||||
|
@ -34,7 +35,69 @@ class MetaFieldsTable extends AppTable
|
|||
->notEmptyString('meta_template_field_id')
|
||||
->requirePresence(['scope', 'field', 'value', 'uuid', 'meta_template_id', 'meta_template_field_id'], 'create');
|
||||
|
||||
// add validation regex
|
||||
$validator->add('value', 'validMetaField', [
|
||||
'rule' => 'isValidMetaField',
|
||||
'message' => __('The provided value doesn\'t satisfy the validation defined by the meta-fields\'s meta-template'),
|
||||
'provider' => 'table',
|
||||
]);
|
||||
|
||||
return $validator;
|
||||
}
|
||||
|
||||
// public function buildRules(RulesChecker $rules): RulesChecker
|
||||
// {
|
||||
// $rules->add([$this, 'isValidMetaField'], 'validMetaField', [
|
||||
// // 'errorField' => 'meta_field.value',
|
||||
// 'errorField' => 'value',
|
||||
// 'message' => __('The provided value doesn\'t satisfy the validation defined by the meta-fields\'s meta-template'),
|
||||
// ]);
|
||||
// return $rules;
|
||||
// }
|
||||
|
||||
public function isValidMetaField($value, array $context)
|
||||
{
|
||||
$metaFieldsTable = $context['providers']['table'];
|
||||
$entityData = $context['data'];
|
||||
$metaTemplateField = $metaFieldsTable->MetaTemplateFields->get($entityData['meta_template_field_id']);
|
||||
$typeValid = $this->isValidType($value, $metaTemplateField['type']);
|
||||
if ($typeValid !== true) {
|
||||
return $typeValid;
|
||||
}
|
||||
if (!empty($metaTemplateField['regex'])) {
|
||||
return $this->isValidRegex($value, $metaTemplateField);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isValidMetaFieldOLD($entity, $options)
|
||||
{
|
||||
debug($entity['value']);
|
||||
$metaFieldsTable = $options['repository'];
|
||||
$metaTemplateField = $metaFieldsTable->MetaTemplateFields->get($entity['meta_template_field_id']);
|
||||
$typeValid = $this->isValidType($entity['value'], $metaTemplateField['type']);
|
||||
if ($typeValid !== true) {
|
||||
return $typeValid;
|
||||
}
|
||||
$metaTemplateField['regex'] = '/123/';
|
||||
if (!empty($metaTemplateField['regex'])) {
|
||||
return $this->isValidRegex($entity['value'], $metaTemplateField);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isValidType($value, string $type)
|
||||
{
|
||||
if (empty($value)) {
|
||||
return __('Metafield value cannot be empty.');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isValidRegex($value, $metaTemplateField)
|
||||
{
|
||||
if (!preg_match($metaTemplateField['regex'], $value)) {
|
||||
return __('Metafield value `{0}` for `{1}` doesn\'t pass regex validation', $value, $metaTemplateField->field);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
'type' => 'tags'
|
||||
),
|
||||
),
|
||||
'metaTemplates' => empty($metaTemplates) ? [] : $metaTemplates,
|
||||
// 'metaTemplates' => empty($metaTemplates) ? [] : $metaTemplates,
|
||||
'submit' => array(
|
||||
'action' => $this->request->getParam('action')
|
||||
)
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
$params[$k] = $fd;
|
||||
}
|
||||
}
|
||||
// debug($fieldData);
|
||||
// debug($params);
|
||||
$temp = $this->element('genericElements/Form/Fields/' . $fieldTemplate, array(
|
||||
'fieldData' => $fieldData,
|
||||
'params' => $params
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
- use these to define dynamic form fields, or anything that will feed into the regular fields via JS population
|
||||
* - submit: The submit button itself. By default it will simply submit to the form as defined via the 'model' field
|
||||
*/
|
||||
// debug(\Cake\Utility\Hash::extract($entity, 'MetaTemplates.{n}.meta_template_fields.{n}.metaFields.{n}.value'));
|
||||
$this->Form->setConfig('errorClass', 'is-invalid');
|
||||
$modelForForm = empty($data['model']) ?
|
||||
h(\Cake\Utility\Inflector::singularize(\Cake\Utility\Inflector::classify($this->request->getParam('controller')))) :
|
||||
|
@ -21,7 +22,6 @@
|
|||
$simpleFieldWhitelist = [
|
||||
'default', 'type', 'placeholder', 'label', 'empty', 'rows', 'div', 'required', 'templates'
|
||||
];
|
||||
//$fieldsArrayForPersistence = array();
|
||||
if (empty($data['url'])) {
|
||||
$data['url'] = ["controller" => $this->request->getParam('controller'), "action" => $this->request->getParam('url')];
|
||||
}
|
||||
|
@ -78,11 +78,10 @@
|
|||
}
|
||||
}
|
||||
$metaTemplateString = '';
|
||||
if (!empty($data['metaTemplates']) && $data['metaTemplates']->count() > 0) {
|
||||
if (!empty($entity['MetaTemplates']) && count($entity['MetaTemplates']) > 0) {
|
||||
$metaTemplateString = $this->element(
|
||||
'genericElements/Form/metaTemplateScaffold',
|
||||
[
|
||||
'metaTemplatesData' => $data['metaTemplates'],
|
||||
'form' => $this->Form,
|
||||
]
|
||||
);
|
||||
|
|
|
@ -10,7 +10,7 @@ $default_template = [
|
|||
$this->Form->setTemplates($default_template);
|
||||
$backupTemplates = $this->Form->getTemplates();
|
||||
$tabData = [];
|
||||
foreach ($metaTemplatesData as $i => $metaTemplate) {
|
||||
foreach ($entity->MetaTemplates as $i => $metaTemplate) {
|
||||
if ($metaTemplate->is_default) {
|
||||
$tabData['navs'][$i] = [
|
||||
'html' => $this->element('/genericElements/MetaTemplates/metaTemplateNav', ['metaTemplate' => $metaTemplate])
|
||||
|
@ -21,6 +21,7 @@ foreach ($metaTemplatesData as $i => $metaTemplate) {
|
|||
];
|
||||
}
|
||||
$fieldsHtml = '';
|
||||
// debug($metaTemplate['meta_template_fields']);
|
||||
foreach ($metaTemplate->meta_template_fields as $metaTemplateField) {
|
||||
$metaTemplateField->label = Inflector::humanize($metaTemplateField->field);
|
||||
if (!empty($metaTemplateField->metaFields)) {
|
||||
|
|
|
@ -39,10 +39,14 @@ $seed = 'mfb-' . mt_rand();
|
|||
|
||||
function addNewField() {
|
||||
const $clicked = $(this);
|
||||
const $lastInputContainer = $clicked.closest('.multi-metafields-container').children().not('.template-container').find('input').last().closest('.multi-metafield-container')
|
||||
const $templateContainer = $clicked.closest('.multi-metafields-container').find('.template-container').children()
|
||||
const $clonedContainer = $templateContainer.clone()
|
||||
$clonedContainer.removeClass('d-none', 'template-container')
|
||||
let $lastInputContainer = $clicked.closest('.multi-metafields-container').children().not('.template-container').find('input').last().closest('.multi-metafield-container')
|
||||
if ($lastInputContainer.length == 0) {
|
||||
$lastInputContainer = $clicked.closest('.multi-metafields-container').find('input').last().closest('.multi-metafield-container')
|
||||
}
|
||||
const $clonedContainer = $lastInputContainer.clone()
|
||||
$clonedContainer
|
||||
.removeClass('has-error')
|
||||
.find('.error-message ').remove()
|
||||
const $clonedInput = $clonedContainer.find('input, select')
|
||||
if ($clonedInput.length > 0) {
|
||||
const injectedTemplateId = $clicked.closest('.multi-metafields-container').find('.new-metafield').length
|
||||
|
@ -63,6 +67,34 @@ $seed = 'mfb-' . mt_rand();
|
|||
.attr('field', dottedPathStr)
|
||||
.attr('name', brackettedPathStr)
|
||||
.val('')
|
||||
.removeClass('is-invalid')
|
||||
}
|
||||
// function addNewField() {
|
||||
// const $clicked = $(this);
|
||||
// const $lastInputContainer = $clicked.closest('.multi-metafields-container').children().not('.template-container').find('input').last().closest('.multi-metafield-container')
|
||||
// const $templateContainer = $clicked.closest('.multi-metafields-container').find('.template-container').children()
|
||||
// const $clonedContainer = $templateContainer.clone()
|
||||
// $clonedContainer.removeClass('d-none', 'template-container')
|
||||
// const $clonedInput = $clonedContainer.find('input, select')
|
||||
// if ($clonedInput.length > 0) {
|
||||
// const injectedTemplateId = $clicked.closest('.multi-metafields-container').find('.new-metafield').length
|
||||
// $clonedInput.addClass('new-metafield')
|
||||
// adjustClonedInputAttr($clonedInput, injectedTemplateId)
|
||||
// $clonedContainer.insertAfter($lastInputContainer)
|
||||
// }
|
||||
// }
|
||||
|
||||
// function adjustClonedInputAttr($input, injectedTemplateId) {
|
||||
// let explodedPath = $input.attr('field').split('.').splice(0, 5)
|
||||
// explodedPath.push('new', injectedTemplateId)
|
||||
// dottedPathStr = explodedPath.join('.')
|
||||
// brackettedPathStr = explodedPath.map((elem, i) => {
|
||||
// return i == 0 ? elem : `[${elem}]`
|
||||
// }).join('')
|
||||
// $input.attr('id', dottedPathStr)
|
||||
// .attr('field', dottedPathStr)
|
||||
// .attr('name', brackettedPathStr)
|
||||
// .val('')
|
||||
// }
|
||||
})()
|
||||
</script>
|
|
@ -4,20 +4,48 @@ use Cake\Utility\Inflector;
|
|||
|
||||
$default_template = [
|
||||
'inputContainer' => '<div class="row mb-1 multi-metafield-container">{{content}}</div>',
|
||||
'inputContainerError' => '<div class="row mb-1 metafield-container has-error">{{content}}</div>',
|
||||
'inputContainerError' => '<div class="row mb-1 multi-metafield-container has-error">{{content}}</div>',
|
||||
'formGroup' => '<label class="col-sm-2 col-form-label form-label" {{attrs}}>{{label}}</label><div class="col-sm-10 multi-metafield-input-container">{{input}}{{error}}</div>',
|
||||
];
|
||||
$form->setTemplates($default_template);
|
||||
|
||||
$fieldsHtml = '';
|
||||
$labelPrintedOnce = false;
|
||||
$newMetaFields = [];
|
||||
$newFieldIndex = 0;
|
||||
// $newMetaFieldPrinted = false;
|
||||
// debug($entity);
|
||||
// debug($entity->getErrors());
|
||||
if (!empty($metaFieldsEntities)) {
|
||||
foreach ($metaFieldsEntities as $i => $metaFieldsEntity) {
|
||||
$metaFieldsEntity->label = Inflector::humanize($metaFieldsEntity->field);
|
||||
$fieldData = [
|
||||
'label' => $metaFieldsEntity->label,
|
||||
'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.%s.value', $metaFieldsEntity->meta_template_id, $metaFieldsEntity->meta_template_field_id, $metaFieldsEntity->id),
|
||||
'field' => sprintf(
|
||||
'MetaTemplates.%s.meta_template_fields.%s.metaFields.%s.value',
|
||||
$metaFieldsEntity->meta_template_id,
|
||||
$metaFieldsEntity->meta_template_field_id,
|
||||
$metaFieldsEntity->id
|
||||
),
|
||||
];
|
||||
if($metaFieldsEntity->isNew()) {
|
||||
$fieldData['field'] = sprintf(
|
||||
'MetaTemplates.%s.meta_template_fields.%s.metaFields.%s.value',
|
||||
$metaFieldsEntity->meta_template_id,
|
||||
$metaFieldsEntity->meta_template_field_id,
|
||||
$i
|
||||
);
|
||||
$fieldData['class'] = 'new-metafield';
|
||||
// $fieldData['field'] = sprintf(
|
||||
// 'MetaTemplates.%s.meta_template_fields.%s.metaFields.new.%s',
|
||||
// $metaFieldsEntity->meta_template_id,
|
||||
// $metaFieldsEntity->meta_template_field_id,
|
||||
// $newFieldIndex
|
||||
// );
|
||||
// $fieldData['class'] = 'new-metafield';
|
||||
// $newMetaFieldPrinted = true;
|
||||
// $newFieldIndex += 1;
|
||||
}
|
||||
if ($labelPrintedOnce) { // Only the first input can have a label
|
||||
$fieldData['label'] = false;
|
||||
}
|
||||
|
@ -35,17 +63,17 @@ if (!empty($metaTemplateField) && !empty($multiple)) { // Add multiple field but
|
|||
$metaTemplateField->label = Inflector::humanize($metaTemplateField->field);
|
||||
$emptyMetaFieldInput = '';
|
||||
if (empty($metaFieldsEntities)) {
|
||||
$emptyMetaFieldInput = $this->element(
|
||||
'genericElements/Form/fieldScaffold',
|
||||
[
|
||||
'fieldData' => [
|
||||
'label' => $metaTemplateField->label,
|
||||
'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new.0', $metaTemplateField->meta_template_id, $metaTemplateField->id),
|
||||
'class' => 'new-metafield',
|
||||
],
|
||||
'form' => $form,
|
||||
]
|
||||
);
|
||||
// $emptyMetaFieldInput = $this->element(
|
||||
// 'genericElements/Form/fieldScaffold',
|
||||
// [
|
||||
// 'fieldData' => [
|
||||
// 'label' => $metaTemplateField->label,
|
||||
// 'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new.0', $metaTemplateField->meta_template_id, $metaTemplateField->id),
|
||||
// 'class' => 'new-metafield',
|
||||
// ],
|
||||
// 'form' => $form,
|
||||
// ]
|
||||
// );
|
||||
}
|
||||
$emptyInputForSecurityComponent = $this->element(
|
||||
'genericElements/Form/fieldScaffold',
|
||||
|
@ -53,10 +81,24 @@ if (!empty($metaTemplateField) && !empty($multiple)) { // Add multiple field but
|
|||
'fieldData' => [
|
||||
'label' => false,
|
||||
'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new[]', $metaTemplateField->meta_template_id, $metaTemplateField->id),
|
||||
'value' => '',
|
||||
],
|
||||
'form' => $form,
|
||||
]
|
||||
);
|
||||
// $emptyInputForSecurityComponent = '';
|
||||
// if (!$newMetaFieldPrinted) {
|
||||
// $emptyInputForSecurityComponent = $this->element(
|
||||
// 'genericElements/Form/fieldScaffold',
|
||||
// [
|
||||
// 'fieldData' => [
|
||||
// 'label' => false,
|
||||
// 'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new[]', $metaTemplateField->meta_template_id, $metaTemplateField->id),
|
||||
// ],
|
||||
// 'form' => $form,
|
||||
// ]
|
||||
// );
|
||||
// }
|
||||
$multiFieldButtonHtml = sprintf(
|
||||
'<div class="row mb-1 multi-metafield-container add-input-container"><div class="col-sm-2 form-label"></div><div class="col-sm-10 multi-metafield-input-container">%s</div></div>',
|
||||
$this->element(
|
||||
|
@ -66,7 +108,7 @@ if (!empty($metaTemplateField) && !empty($multiple)) { // Add multiple field but
|
|||
]
|
||||
)
|
||||
);
|
||||
$fieldsHtml .= $emptyMetaFieldInput;
|
||||
// $fieldsHtml .= $emptyMetaFieldInput;
|
||||
$fieldsHtml .= sprintf('<div class="d-none template-container">%s</div>', $emptyInputForSecurityComponent);
|
||||
$fieldsHtml .= $multiFieldButtonHtml;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue