diff --git a/modules/backend/behaviors/RelationController.php b/modules/backend/behaviors/RelationController.php index f6c2caa30..f7b28167a 100644 --- a/modules/backend/behaviors/RelationController.php +++ b/modules/backend/behaviors/RelationController.php @@ -22,6 +22,11 @@ class RelationController extends ControllerBehavior */ const PARAM_FIELD = '_relation_field'; + /** + * @var const Postback parameter for the active management mode. + */ + const PARAM_MODE = '_relation_mode'; + /** * @var Backend\Classes\WidgetBase Reference to the search widget object. */ @@ -107,6 +112,16 @@ class RelationController extends ControllerBehavior */ protected $alias; + /** + * @var array The set of buttons to display in view mode. + */ + protected $toolbarButtons; + + /** + * @var Model Reference to the model used for viewing (form only). + */ + protected $viewModel; + /** * @var string Relation has many (multi) or has one (single). */ @@ -200,8 +215,9 @@ class RelationController extends ControllerBehavior $this->relationModel = $this->relationObject->getRelated(); $this->readOnly = $this->getConfig('readOnly'); - $this->viewMode = $this->evalViewMode(); - $this->manageMode = $this->evalManageMode(); + $this->toolbarButtons = $this->evalToolbarButtons(); + $this->viewMode = $this->viewMode ?: $this->evalViewMode(); + $this->manageMode = $this->manageMode ?: $this->evalManageMode(); $this->manageId = post('manage_id'); /* @@ -235,6 +251,33 @@ class RelationController extends ControllerBehavior } } + /** + * Determine the default buttons based on the model relationship type. + * @return string + */ + protected function evalToolbarButtons() + { + if ($buttons = $this->getConfig('view[toolbarButtons]')) { + return is_array($buttons) + ? $buttons + : array_map('trim', explode('|', $buttons)); + } + + switch ($this->relationType) { + case 'hasMany': + return ['add', 'create', 'delete', 'remove']; + + case 'belongsToMany': + return ['create', 'add', 'remove']; + + case 'belongsTo': + return ['create', 'update', 'link', 'delete', 'unlink']; + + case 'hasOne': + return ['create', 'update', 'link', 'delete', 'unlink']; + } + } + /** * Determine the view mode based on the model relationship type. * @return string @@ -258,6 +301,10 @@ class RelationController extends ControllerBehavior */ protected function evalManageMode() { + if ($mode = post(self::PARAM_MODE)) { + return $mode; + } + switch ($this->relationType) { case 'belongsTo': $mode = 'list'; @@ -386,8 +433,10 @@ class RelationController extends ControllerBehavior $this->vars['relationToolbarWidget'] = $this->toolbarWidget; $this->vars['relationManageMode'] = $this->manageMode; $this->vars['relationManageWidget'] = $this->manageWidget; + $this->vars['relationToolbarButtons'] = $this->toolbarButtons; $this->vars['relationViewMode'] = $this->viewMode; $this->vars['relationViewWidget'] = $this->viewWidget; + $this->vars['relationViewModel'] = $this->viewModel; $this->vars['relationPivotWidget'] = $this->pivotWidget; $this->vars['relationSessionKey'] = $this->relationGetSessionKey(); } @@ -482,11 +531,13 @@ class RelationController extends ControllerBehavior public function onRelationButtonAdd() { + $this->manageMode = 'list'; return $this->onRelationManageForm(); } public function onRelationButtonCreate() { + $this->manageMode = 'form'; return $this->onRelationManageForm(); } @@ -497,6 +548,7 @@ class RelationController extends ControllerBehavior public function onRelationButtonLink() { + $this->manageMode = 'list'; return $this->onRelationManageForm(); } @@ -512,6 +564,7 @@ class RelationController extends ControllerBehavior public function onRelationButtonUpdate() { + $this->manageMode = 'form'; return $this->onRelationManageForm(); } @@ -539,16 +592,32 @@ class RelationController extends ControllerBehavior */ public function onRelationManageCreate() { + $this->manageMode = 'form'; $this->beforeAjax(); $saveData = $this->manageWidget->getSaveData(); if ($this->viewMode == 'multi') { - $newModel = $this->relationObject->create($saveData, $this->relationGetSessionKey(true)); + if ($this->relationType == 'hasMany') { + $newModel = $this->relationObject->create($saveData, $this->relationGetSessionKey(true)); + } + elseif ($this->relationType == 'belongsToMany') { + $newModel = $this->relationObject->create($saveData, [], $this->relationGetSessionKey(true)); + } + $newModel->commitDeferred($this->manageWidget->getSessionKey()); } elseif ($this->viewMode == 'single') { + $newModel = $this->viewModel; $this->viewWidget->setFormValues($saveData); - $this->viewWidget->model->save(); + + if ($this->relationType == 'belongsTo') { + $newModel->save(); + $this->relationObject->associate($newModel); + $this->relationObject->getParent()->save(); + } + elseif ($this->relationType == 'hasOne') { + $this->relationObject->add($newModel); + } } return $this->relationRefresh(); @@ -559,6 +628,7 @@ class RelationController extends ControllerBehavior */ public function onRelationManageUpdate() { + $this->manageMode = 'form'; $this->beforeAjax(); $saveData = $this->manageWidget->getSaveData(); @@ -568,7 +638,7 @@ class RelationController extends ControllerBehavior } elseif ($this->viewMode == 'single') { $this->viewWidget->setFormValues($saveData); - $this->viewWidget->model->save(); + $this->viewModel->save(); } return ['#'.$this->relationGetId('view') => $this->relationRenderView()]; @@ -600,13 +670,13 @@ class RelationController extends ControllerBehavior * Single (belongs to, has one) */ elseif ($this->viewMode == 'single') { - $relatedModel = $this->viewWidget->model; + $relatedModel = $this->viewModel; if ($relatedModel->exists) { $relatedModel->delete(); } $this->viewWidget->setFormValues([]); - $this->viewWidget->model = $this->relationModel; + $this->viewModel = $this->relationModel; } return $this->relationRefresh(); @@ -654,9 +724,16 @@ class RelationController extends ControllerBehavior */ elseif ($this->viewMode == 'single') { if ($recordId && ($model = $this->relationModel->find($recordId))) { - $this->relationObject->associate($model); - $this->relationObject->getParent()->save(); + + if ($this->relationType == 'belongsTo') { + $this->relationObject->associate($model); + $this->relationObject->getParent()->save(); + } + elseif ($this->relationType == 'hasOne') { + $this->relationObject->add($model); + } $this->viewWidget->setFormValues($model->attributes); + } } @@ -664,7 +741,7 @@ class RelationController extends ControllerBehavior } /** - * Remove an existing related model from the primary model (join table only) + * Remove an existing related model from the primary model */ public function onRelationManageRemove() { @@ -680,15 +757,38 @@ class RelationController extends ControllerBehavior $checkedIds = $recordId ? [$recordId] : post('checked'); if (is_array($checkedIds)) { - $this->relationObject->detach($checkedIds); + + if ($this->relationType == 'belongsToMany') { + $this->relationObject->detach($checkedIds); + } + elseif ($this->relationType == 'hasMany') { + $relatedModel = $this->relationObject->getRelated(); + foreach ($checkedIds as $relationId) { + if ($obj = $relatedModel->find($relationId)) { + $this->relationObject->remove($obj); + } + } + } + } } /* * Unlink */ elseif ($this->viewMode == 'single') { - $this->relationObject->dissociate(); - $this->relationObject->getParent()->save(); + if ($this->relationType == 'belongsTo') { + $this->relationObject->dissociate(); + $this->relationObject->getParent()->save(); + } + elseif ($this->relationType == 'hasOne') { + if ($obj = $this->relationModel->find($recordId)) { + $this->relationObject->remove($obj); + } + elseif ($this->viewModel->exists) { + $this->relationObject->remove($this->viewModel); + } + } + $this->viewWidget->setFormValues([]); } @@ -762,7 +862,7 @@ class RelationController extends ControllerBehavior $defaultButtons = '~/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm'; } - $defaultConfig['buttons'] = $this->getConfig('view[toolbarButtons]', $defaultButtons); + $defaultConfig['buttons'] = $this->getConfig('view[toolbarPartial]', $defaultButtons); /* * Make config @@ -856,10 +956,10 @@ class RelationController extends ControllerBehavior elseif ($this->viewMode == 'single') { $query = $this->relationObject; $this->controller->relationExtendQuery($query, $this->field); - $model = $query->getResults() ?: $this->relationModel; + $this->viewModel = $query->getResults() ?: $this->relationModel; $config = $this->makeConfig($this->config->form); - $config->model = $model; + $config->model = $this->viewModel; $config->arrayName = class_basename($this->relationModel); $config->context = 'relation'; $config->alias = $this->alias . 'ViewForm'; diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_create.htm b/modules/backend/behaviors/relationcontroller/partials/_button_create.htm index b4e3ec610..eddc92c79 100644 --- a/modules/backend/behaviors/relationcontroller/partials/_button_create.htm +++ b/modules/backend/behaviors/relationcontroller/partials/_button_create.htm @@ -2,6 +2,6 @@ data-control="popup" data-handler="onRelationButtonCreate" href="javascript:;" - class="btn btn-sm btn-primary oc-icon-plus"> + class="btn btn-sm btn-primary oc-icon-file-o"> trans($relationLabel)])) ?> diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_remove.htm b/modules/backend/behaviors/relationcontroller/partials/_button_remove.htm index 6d318b7fe..92a0d27c5 100644 --- a/modules/backend/behaviors/relationcontroller/partials/_button_remove.htm +++ b/modules/backend/behaviors/relationcontroller/partials/_button_remove.htm @@ -1,13 +1,22 @@ - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/modules/backend/behaviors/relationcontroller/partials/_button_unlink.htm b/modules/backend/behaviors/relationcontroller/partials/_button_unlink.htm index ba2e46e57..479e8d9dd 100644 --- a/modules/backend/behaviors/relationcontroller/partials/_button_unlink.htm +++ b/modules/backend/behaviors/relationcontroller/partials/_button_unlink.htm @@ -4,5 +4,5 @@ data-request="onRelationButtonUnlink" data-request-confirm="" data-stripe-load-indicator> - trans($relationLabel)])) ?> + diff --git a/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm b/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm index 7905f0a64..76f9d620a 100644 --- a/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm +++ b/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm @@ -1,5 +1,18 @@
+ + + + relationMakePartial('button_update', [ + 'relationManageId' => $relationViewModel->id + ]) ?> + + relationMakePartial('button_'.$button) ?> + + + + + relationMakePartial('button_create') ?> @@ -25,7 +38,7 @@ - +*/ ?>
diff --git a/modules/backend/lang/en/lang.php b/modules/backend/lang/en/lang.php index 6f86debef..12ca971f1 100644 --- a/modules/backend/lang/en/lang.php +++ b/modules/backend/lang/en/lang.php @@ -187,6 +187,7 @@ return [ 'concurrency_file_changed_description' => "The file you're editing has been changed on disk by another user. You can either reload the file and lose your changes or override the file on the disk." ], 'relation' => [ + 'missing_config' => "Relation behavior does not have any configuration for ':config'.", 'missing_definition' => "Relation behavior does not contain a definition for ':field'.", 'missing_model' => "Relation behavior used in :class does not have a model defined.", 'invalid_action_single' => "This action cannot be performed on a singular relationship.",