chg: [behavior:meta_field] Better integration in CRUD and tables

pull/93/head
Sami Mokaddem 2021-11-09 08:59:17 +01:00
parent f62caa919b
commit a0f6c6a7e0
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
5 changed files with 78 additions and 71 deletions

View File

@ -12,6 +12,7 @@ use Cake\ORM\TableRegistry;
use Cake\Routing\Router; use Cake\Routing\Router;
use Cake\Http\Exception\MethodNotAllowedException; use Cake\Http\Exception\MethodNotAllowedException;
use Cake\Http\Exception\NotFoundException; use Cake\Http\Exception\NotFoundException;
use Cake\Collection\Collection;
class CRUDComponent extends Component class CRUDComponent extends Component
{ {
@ -116,25 +117,27 @@ class CRUDComponent extends Component
private function getMetaTemplates() private function getMetaTemplates()
{ {
$metaTemplates = []; $metaTemplates = [];
if (!empty($this->Table->metaFields)) { if (!$this->Table->hasBehavior('MetaFields')) {
$metaQuery = $this->MetaTemplates->find(); throw new \Exception(__("Table {$this->TableAlias} does not support meta_fields"));
$metaQuery
->order(['is_default' => 'DESC'])
->where([
'scope' => $this->Table->metaFields,
'enabled' => 1
])
->contain('MetaTemplateFields')
->formatResults(function (\Cake\Collection\CollectionInterface $metaTemplates) { // Set meta-template && meta-template-fields indexed by their ID
return $metaTemplates
->map(function ($metaTemplate) {
$metaTemplate->meta_template_fields = Hash::combine($metaTemplate->meta_template_fields, '{n}.id', '{n}');
return $metaTemplate;
})
->indexBy('id');
});
$metaTemplates = $metaQuery->all();
} }
$metaFieldsBehavior = $this->Table->getBehavior('MetaFields');
$metaQuery = $this->MetaTemplates->find();
$metaQuery
->order(['is_default' => 'DESC'])
->where([
'scope' => $metaFieldsBehavior->getScope(),
'enabled' => 1
])
->contain('MetaTemplateFields')
->formatResults(function (\Cake\Collection\CollectionInterface $metaTemplates) { // Set meta-template && meta-template-fields indexed by their ID
return $metaTemplates
->map(function ($metaTemplate) {
$metaTemplate->meta_template_fields = Hash::combine($metaTemplate->meta_template_fields, '{n}.id', '{n}');
return $metaTemplate;
})
->indexBy('id');
});
$metaTemplates = $metaQuery->all();
return $metaTemplates; return $metaTemplates;
} }
@ -142,7 +145,7 @@ class CRUDComponent extends Component
{ {
$metaTemplates = $this->getMetaTemplates(); $metaTemplates = $this->getMetaTemplates();
$data = $this->Table->newEmptyEntity(); $data = $this->Table->newEmptyEntity();
// $data = $this->attachMetaTemplates($data, $metaTemplates->toArray()); $data = $this->attachMetaTemplates($data, $metaTemplates->toArray());
if (!empty($params['fields'])) { if (!empty($params['fields'])) {
$this->Controller->set('fields', $params['fields']); $this->Controller->set('fields', $params['fields']);
} }
@ -158,6 +161,9 @@ class CRUDComponent extends Component
if (!empty($params['fields'])) { if (!empty($params['fields'])) {
$patchEntityParams['fields'] = $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'];
$data = $this->Table->patchEntity($data, $input, $patchEntityParams); $data = $this->Table->patchEntity($data, $input, $patchEntityParams);
if (isset($params['beforeSave'])) { if (isset($params['beforeSave'])) {
$data = $params['beforeSave']($data); $data = $params['beforeSave']($data);
@ -168,9 +174,6 @@ class CRUDComponent extends Component
$params['afterSave']($data); $params['afterSave']($data);
} }
$message = __('{0} added.', $this->ObjectAlias); $message = __('{0} added.', $this->ObjectAlias);
if (!empty($input['metaFields'])) {
$this->saveMetaFields($data->id, $input);
}
if ($this->Controller->ParamHandler->isRest()) { if ($this->Controller->ParamHandler->isRest()) {
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json'); $this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
} else if ($this->Controller->ParamHandler->isAjax()) { } else if ($this->Controller->ParamHandler->isAjax()) {
@ -252,7 +255,7 @@ class CRUDComponent extends Component
// prune empty values and marshall fields // prune empty values and marshall fields
private function massageMetaFields($entity, $input, $allMetaTemplates=[]) private function massageMetaFields($entity, $input, $allMetaTemplates=[])
{ {
if (empty($input['MetaTemplates'])) { if (empty($input['MetaTemplates'] || !$this->Table->hasBehavior('MetaFields'))) {
return ['entity' => $entity, 'metafields_to_delete' => []]; return ['entity' => $entity, 'metafields_to_delete' => []];
} }
@ -261,8 +264,12 @@ class CRUDComponent extends Component
if (empty($metaTemplates)) { if (empty($metaTemplates)) {
$allMetaTemplates = $this->getMetaTemplates()->toArray(); $allMetaTemplates = $this->getMetaTemplates()->toArray();
} }
foreach ($entity->meta_fields as $i => $metaField) { if (!empty($entity->meta_fields)) {
$metaFieldsIndex[$metaField->id] = $i; foreach ($entity->meta_fields as $i => $metaField) {
$metaFieldsIndex[$metaField->id] = $i;
}
} else {
$entity->meta_fields = [];
} }
$metaFieldsToDelete = []; $metaFieldsToDelete = [];
@ -277,7 +284,7 @@ class CRUDComponent extends Component
$metaField = $metaFieldsTable->newEmptyEntity(); $metaField = $metaFieldsTable->newEmptyEntity();
$metaFieldsTable->patchEntity($metaField, [ $metaFieldsTable->patchEntity($metaField, [
'value' => $new_value, 'value' => $new_value,
'scope' => $this->Table->metaFields, // get scope from behavior 'scope' => $this->Table->getBehavior('MetaFields')->getScope(),
'field' => $rawMetaTemplateField->field, 'field' => $rawMetaTemplateField->field,
'meta_template_id' => $rawMetaTemplateField->meta_template_id, 'meta_template_id' => $rawMetaTemplateField->meta_template_id,
'meta_template_field_id' => $rawMetaTemplateField->id, 'meta_template_field_id' => $rawMetaTemplateField->id,
@ -286,13 +293,11 @@ class CRUDComponent extends Component
]); ]);
$entity->meta_fields[] = $metaField; $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[] = $metaField;
// $entity->MetaTemplates[$template_id]->meta_template_fields[$meta_template_field_id]->metaFields['new'][] = $metaField;
} }
} }
} else { } else {
$new_value = $meta_field['value']; $new_value = $meta_field['value'];
if (!empty($new_value)) { if (!empty($new_value)) { // update meta_field and attach validation errors
// update meta_field and attach validation errors
if (!empty($metaFieldsIndex[$meta_field_id])) { if (!empty($metaFieldsIndex[$meta_field_id])) {
$index = $metaFieldsIndex[$meta_field_id]; $index = $metaFieldsIndex[$meta_field_id];
$metaFieldsTable->patchEntity($entity->meta_fields[$index], [ $metaFieldsTable->patchEntity($entity->meta_fields[$index], [
@ -307,7 +312,7 @@ class CRUDComponent extends Component
$metaField = $metaFieldsTable->newEmptyEntity(); $metaField = $metaFieldsTable->newEmptyEntity();
$metaFieldsTable->patchEntity($metaField, [ $metaFieldsTable->patchEntity($metaField, [
'value' => $new_value, 'value' => $new_value,
'scope' => $this->Table->metaFields, // get scope from behavior 'scope' => $this->Table->getBehavior('MetaFields')->getScope(), // get scope from behavior
'field' => $rawMetaTemplateField->field, 'field' => $rawMetaTemplateField->field,
'meta_template_id' => $rawMetaTemplateField->meta_template_id, 'meta_template_id' => $rawMetaTemplateField->meta_template_id,
'meta_template_field_id' => $rawMetaTemplateField->id, 'meta_template_field_id' => $rawMetaTemplateField->id,
@ -317,8 +322,7 @@ class CRUDComponent extends Component
$entity->meta_fields[] = $metaField; $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[] = $metaField;
} }
} else { } else { // Metafield value is empty, indicating the field should be removed
// Metafield value is empty, indicating the field should be removed
$index = $metaFieldsIndex[$meta_field_id]; $index = $metaFieldsIndex[$meta_field_id];
$metaFieldsToDelete[] = $entity->meta_fields[$index]; $metaFieldsToDelete[] = $entity->meta_fields[$index];
unset($entity->meta_fields[$index]); unset($entity->meta_fields[$index]);
@ -356,7 +360,6 @@ class CRUDComponent extends Component
if (empty($id)) { if (empty($id)) {
throw new NotFoundException(__('Invalid {0}.', $this->ObjectAlias)); throw new NotFoundException(__('Invalid {0}.', $this->ObjectAlias));
} }
$metaTemplates = $this->getMetaTemplates();
if ($this->taggingSupported()) { if ($this->taggingSupported()) {
$params['contain'][] = 'Tags'; $params['contain'][] = 'Tags';
$this->setAllTags(); $this->setAllTags();
@ -373,7 +376,7 @@ class CRUDComponent extends Component
} }
} }
$data = $this->Table->get($id, $getParam); $data = $this->Table->get($id, $getParam);
$data = $this->attachMetaTemplates($data, $metaTemplates->toArray()); $data = $this->attachMetaTemplatesIfNeeded($data);
if (!empty($params['fields'])) { if (!empty($params['fields'])) {
$this->Controller->set('fields', $params['fields']); $this->Controller->set('fields', $params['fields']);
} }
@ -385,10 +388,12 @@ class CRUDComponent extends Component
if (!empty($params['fields'])) { if (!empty($params['fields'])) {
$patchEntityParams['fields'] = $params['fields']; $patchEntityParams['fields'] = $params['fields'];
} }
$massagedData = $this->massageMetaFields($data, $input, $metaTemplates); if ($this->Table->hasBehavior('MetaFields')) {
unset($input['MetaTemplates']); // Avoid MetaTemplates to be overriden when patching entity $massagedData = $this->massageMetaFields($data, $input, $metaTemplates);
$data = $massagedData['entity']; unset($input['MetaTemplates']); // Avoid MetaTemplates to be overriden when patching entity
$metaFieldsToDelete = $massagedData['metafields_to_delete']; $data = $massagedData['entity'];
$metaFieldsToDelete = $massagedData['metafields_to_delete'];
}
$data = $this->Table->patchEntity($data, $input, $patchEntityParams); $data = $this->Table->patchEntity($data, $input, $patchEntityParams);
if (isset($params['beforeSave'])) { if (isset($params['beforeSave'])) {
$data = $params['beforeSave']($data); $data = $params['beforeSave']($data);
@ -436,10 +441,10 @@ class CRUDComponent extends Component
public function attachMetaData($id, $data) public function attachMetaData($id, $data)
{ {
if (empty($this->Table->metaFields)) { if (!$this->Table->hasBehavior('MetaFields')) {
return $data; throw new \Exception(__("Table {$this->TableAlias} does not support meta_fields"));
} }
$metaFieldScope = $this->Table->metaFields; $metaFieldScope = $this->Table->getBehavior('MetaFields')->getScope();
$query = $this->MetaTemplates->find()->where(['MetaTemplates.scope' => $metaFieldScope]); $query = $this->MetaTemplates->find()->where(['MetaTemplates.scope' => $metaFieldScope]);
$query->contain(['MetaTemplateFields.MetaFields' => function ($q) use ($id, $metaFieldScope) { $query->contain(['MetaTemplateFields.MetaFields' => function ($q) use ($id, $metaFieldScope) {
return $q->where(['MetaFields.scope' => $metaFieldScope, 'MetaFields.parent_id' => $id]); return $q->where(['MetaFields.scope' => $metaFieldScope, 'MetaFields.parent_id' => $id]);
@ -468,28 +473,13 @@ class CRUDComponent extends Component
return $metaTemplates; return $metaTemplates;
} }
// public function getMetaFields($id, $data)
// {
// if (empty($this->Table->metaFields)) {
// return $data;
// }
// $query = $this->MetaFields->find();
// $query->where(['MetaFields.scope' => $this->Table->metaFields, 'MetaFields.parent_id' => $id]);
// $metaFields = $query->all();
// $data['metaFields'] = [];
// foreach($metaFields as $metaField) {
// // $data['metaFields'][$metaField->meta_template_id][$metaField->field] = $metaField->value;
// $data['metaFields'][$metaField->meta_template_id][$metaField->meta_template_field_id] = $metaField->value;
// }
// return $data;
// }
public function getMetaFields($id) public function getMetaFields($id)
{ {
if (empty($this->Table->metaFields)) { if (!$this->Table->hasBehavior('MetaFields')) {
return $data; throw new \Exception(__("Table {$this->TableAlias} does not support meta_fields"));
} }
$query = $this->MetaFields->find(); $query = $this->MetaFields->find();
$query->where(['MetaFields.scope' => $this->Table->metaFields, 'MetaFields.parent_id' => $id]); $query->where(['MetaFields.scope' => $this->Table->getBehavior('MetaFields')->getScope(), 'MetaFields.parent_id' => $id]);
$metaFields = $query->all(); $metaFields = $query->all();
$data = []; $data = [];
foreach ($metaFields as $metaField) { foreach ($metaFields as $metaField) {
@ -503,7 +493,10 @@ class CRUDComponent extends Component
public function attachMetaTemplates($data, $metaTemplates) public function attachMetaTemplates($data, $metaTemplates)
{ {
$metaFields = $this->getMetaFields($data->id, $data); $metaFields = [];
if (!empty($data->id)) {
$metaFields = $this->getMetaFields($data->id, $data);
}
foreach ($metaTemplates as $i => $metaTemplate) { foreach ($metaTemplates as $i => $metaTemplate) {
if (isset($metaFields[$metaTemplate->id])) { if (isset($metaFields[$metaTemplate->id])) {
foreach ($metaTemplate->meta_template_fields as $j => $meta_template_field) { foreach ($metaTemplate->meta_template_fields as $j => $meta_template_field) {
@ -538,9 +531,8 @@ class CRUDComponent extends Component
} }
$data = $this->Table->get($id, $params); $data = $this->Table->get($id, $params);
$metaTemplates = $this->getMetaTemplates(); $data = $this->attachMetaTemplatesIfNeeded($data);
$data = $this->attachMetaTemplates($data, $metaTemplates->toArray());
// $data = $this->attachMetaData($id, $data);
if (isset($params['afterFind'])) { if (isset($params['afterFind'])) {
$data = $params['afterFind']($data); $data = $params['afterFind']($data);
} }
@ -550,6 +542,16 @@ class CRUDComponent extends Component
$this->Controller->set('entity', $data); $this->Controller->set('entity', $data);
} }
public function attachMetaTemplatesIfNeeded($data)
{
if (!$this->Table->hasBehavior('MetaFields')) {
return $data;
}
$metaTemplates = $this->getMetaTemplates();
$data = $this->attachMetaTemplates($data, $metaTemplates->toArray());
return $data;
}
public function delete($id = false): void public function delete($id = false): void
{ {
if ($this->request->is('get')) { if ($this->request->is('get')) {
@ -1028,7 +1030,7 @@ class CRUDComponent extends Component
throw new Exception('Invalid passed conditions'); throw new Exception('Invalid passed conditions');
} }
foreach ($metaANDConditions as $i => $conditions) { foreach ($metaANDConditions as $i => $conditions) {
$metaANDConditions[$i]['scope'] = $this->Table->metaFields; $metaANDConditions[$i]['scope'] = $this->Table->getBehavior('MetaFields')->getScope();
} }
$firstCondition = $this->prefixConditions('MetaFields', $metaANDConditions[0]); $firstCondition = $this->prefixConditions('MetaFields', $metaANDConditions[0]);
$conditionsToJoin = array_slice($metaANDConditions, 1); $conditionsToJoin = array_slice($metaANDConditions, 1);

View File

@ -42,6 +42,8 @@ class MetaFieldsBehavior extends Behavior
], ],
]; ];
private $aliasScope = null;
public function initialize(array $config): void public function initialize(array $config): void
{ {
$this->bindAssociations(); $this->bindAssociations();
@ -49,6 +51,15 @@ class MetaFieldsBehavior extends Behavior
$this->_metaTemplateTable = $this->_table; $this->_metaTemplateTable = $this->_table;
} }
public function getScope()
{
if (is_null($this->aliasScope)) {
$this->aliasScope = Inflector::underscore(Inflector::singularize($this->_table->getAlias()));
}
return $this->aliasScope;
}
public function bindAssociations() public function bindAssociations()
{ {
$config = $this->getConfig(); $config = $this->getConfig();
@ -59,7 +70,7 @@ class MetaFieldsBehavior extends Behavior
$tableAlias = $this->_table->getAlias(); $tableAlias = $this->_table->getAlias();
$assocConditions = [ $assocConditions = [
'MetaFields.scope' => Inflector::underscore(Inflector::singularize($tableAlias)) 'MetaFields.scope' => $this->getScope()
]; ];
if (!$table->hasAssociation('MetaFields')) { if (!$table->hasAssociation('MetaFields')) {
$table->hasMany('MetaFields', array_merge( $table->hasMany('MetaFields', array_merge(

View File

@ -8,8 +8,6 @@ use Cake\Validation\Validator;
class IndividualsTable extends AppTable class IndividualsTable extends AppTable
{ {
public $metaFields = 'individual';
public function initialize(array $config): void public function initialize(array $config): void
{ {
parent::initialize($config); parent::initialize($config);

View File

@ -8,8 +8,6 @@ use Cake\Validation\Validator;
class MetaTemplatesTable extends AppTable class MetaTemplatesTable extends AppTable
{ {
public $metaFields = true;
public function initialize(array $config): void public function initialize(array $config): void
{ {
parent::initialize($config); parent::initialize($config);

View File

@ -9,8 +9,6 @@ use Cake\Error\Debugger;
class OrganisationsTable extends AppTable class OrganisationsTable extends AppTable
{ {
public $metaFields = 'organisation';
protected $_accessible = [ protected $_accessible = [
'id' => false 'id' => false
]; ];