Full pivot support added to RelationController
This commit is contained in:
parent
4feb64fef3
commit
398177b006
|
|
@ -1,3 +1,9 @@
|
||||||
|
* **Build 22x** (2015-03-xx)
|
||||||
|
- Belongs-to-many model relations now support defining a custom pivot model with the `pivotModel` option (see Database > Model docs).
|
||||||
|
- The config definitions for behavior `RelationController` have been refactored. When using `pivot` mode all columns and fields should now reside in a `pivot[]` array (see Backend > Relations docs).
|
||||||
|
- Record Finder form widget now supports nested attributes for relations.
|
||||||
|
- List columns now support using array names (eg: `relation[attribute]`) which acts as an alias for the `valueFrom` option with `searchable` and `sortable` disabled.
|
||||||
|
|
||||||
* **Build 226** (2015-03-16)
|
* **Build 226** (2015-03-16)
|
||||||
- Form Tabs now support specifying a default tab using the `defaultTab` option (see Backend > Forms docs).
|
- Form Tabs now support specifying a default tab using the `defaultTab` option (see Backend > Forms docs).
|
||||||
- Improved the Theme management features: Edit properties, import, export, duplicate and delete.
|
- Improved the Theme management features: Edit properties, import, export, duplicate and delete.
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ use Event;
|
||||||
use Input;
|
use Input;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
use Backend;
|
use Backend;
|
||||||
use Backend\Classes\FormField;
|
|
||||||
use Backend\Classes\ControllerBehavior;
|
use Backend\Classes\ControllerBehavior;
|
||||||
use October\Rain\Router\Helper as RouterHelper;
|
use October\Rain\Router\Helper as RouterHelper;
|
||||||
use ApplicationException;
|
use ApplicationException;
|
||||||
|
|
@ -22,6 +21,8 @@ use Exception;
|
||||||
*/
|
*/
|
||||||
class FormController extends ControllerBehavior
|
class FormController extends ControllerBehavior
|
||||||
{
|
{
|
||||||
|
use \Backend\Traits\FormModelSaver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string Default context for "create" pages.
|
* @var string Default context for "create" pages.
|
||||||
*/
|
*/
|
||||||
|
|
@ -59,11 +60,6 @@ class FormController extends ControllerBehavior
|
||||||
*/
|
*/
|
||||||
protected $context;
|
protected $context;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array List of prepared models that require saving.
|
|
||||||
*/
|
|
||||||
protected $modelsToSave = [];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Model The initialized model used by the form.
|
* @var Model The initialized model used by the form.
|
||||||
*/
|
*/
|
||||||
|
|
@ -701,43 +697,4 @@ class FormController extends ControllerBehavior
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Internals
|
|
||||||
//
|
|
||||||
|
|
||||||
protected function prepareModelsToSave($model, $saveData)
|
|
||||||
{
|
|
||||||
$this->modelsToSave = [];
|
|
||||||
$this->setModelAttributes($model, $saveData);
|
|
||||||
return $this->modelsToSave;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a data collection to a model attributes, relations will also be set.
|
|
||||||
* @param array $saveData Data to save.
|
|
||||||
* @param Model $model Model to save to
|
|
||||||
* @return array The collection of models to save.
|
|
||||||
*/
|
|
||||||
protected function setModelAttributes($model, $saveData)
|
|
||||||
{
|
|
||||||
$this->modelsToSave[] = $model;
|
|
||||||
|
|
||||||
if (!is_array($saveData)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$singularTypes = ['belongsTo', 'hasOne', 'morphOne'];
|
|
||||||
foreach ($saveData as $attribute => $value) {
|
|
||||||
if (
|
|
||||||
is_array($value) &&
|
|
||||||
$model->hasRelation($attribute) &&
|
|
||||||
in_array($model->getRelationType($attribute), $singularTypes)
|
|
||||||
) {
|
|
||||||
$this->setModelAttributes($model->{$attribute}, $value);
|
|
||||||
}
|
|
||||||
elseif ($value !== FormField::NO_SAVE_DATA) {
|
|
||||||
$model->{$attribute} = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ use October\Rain\Database\Model;
|
||||||
*/
|
*/
|
||||||
class RelationController extends ControllerBehavior
|
class RelationController extends ControllerBehavior
|
||||||
{
|
{
|
||||||
|
use \Backend\Traits\FormModelSaver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var const Postback parameter for the active relationship field.
|
* @var const Postback parameter for the active relationship field.
|
||||||
*/
|
*/
|
||||||
|
|
@ -272,89 +274,6 @@ 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':
|
|
||||||
case 'belongsToMany':
|
|
||||||
return ['create', 'add', 'delete', 'remove'];
|
|
||||||
|
|
||||||
case 'hasOne':
|
|
||||||
case 'belongsTo':
|
|
||||||
return ['create', 'update', 'link', 'delete', 'unlink'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the view mode based on the model relationship type.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function evalViewMode()
|
|
||||||
{
|
|
||||||
if ($this->forceViewMode) {
|
|
||||||
return $this->forceViewMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($this->relationType) {
|
|
||||||
case 'hasMany':
|
|
||||||
case 'belongsToMany':
|
|
||||||
return 'multi';
|
|
||||||
|
|
||||||
case 'hasOne':
|
|
||||||
case 'belongsTo':
|
|
||||||
return 'single';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the management mode based on the relation type and settings.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function evalManageMode()
|
|
||||||
{
|
|
||||||
if ($mode = post(self::PARAM_MODE)) {
|
|
||||||
return $mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->forceManageMode) {
|
|
||||||
return $this->forceManageMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($this->eventTarget) {
|
|
||||||
case 'button-create':
|
|
||||||
case 'button-update':
|
|
||||||
return 'form';
|
|
||||||
|
|
||||||
case 'button-link':
|
|
||||||
return 'list';
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($this->relationType) {
|
|
||||||
case 'belongsTo':
|
|
||||||
return 'list';
|
|
||||||
|
|
||||||
case 'belongsToMany':
|
|
||||||
if (isset($this->config->pivot)) return 'pivot';
|
|
||||||
elseif ($this->eventTarget == 'list') return 'form';
|
|
||||||
else return 'list';
|
|
||||||
|
|
||||||
case 'hasOne':
|
|
||||||
case 'hasMany':
|
|
||||||
if ($this->eventTarget == 'button-add') return 'list';
|
|
||||||
else return 'form';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the relationship manager.
|
* Renders the relationship manager.
|
||||||
* @param string $field The relationship field.
|
* @param string $field The relationship field.
|
||||||
|
|
@ -889,8 +808,14 @@ class RelationController extends ControllerBehavior
|
||||||
{
|
{
|
||||||
$this->beforeAjax();
|
$this->beforeAjax();
|
||||||
|
|
||||||
|
$foreignKeyName = $this->relationModel->getQualifiedKeyName();
|
||||||
|
$hydratedModel = $this->relationObject->where($foreignKeyName, $this->manageId)->first();
|
||||||
$saveData = $this->pivotWidget->getSaveData();
|
$saveData = $this->pivotWidget->getSaveData();
|
||||||
$this->relationObject->updateExistingPivot($this->manageId, $saveData, true);
|
|
||||||
|
$modelsToSave = $this->prepareModelsToSave($hydratedModel, $saveData);
|
||||||
|
foreach ($modelsToSave as $modelToSave) {
|
||||||
|
$modelToSave->save();
|
||||||
|
}
|
||||||
|
|
||||||
return ['#'.$this->relationGetId('view') => $this->relationRenderView()];
|
return ['#'.$this->relationGetId('view') => $this->relationRenderView()];
|
||||||
}
|
}
|
||||||
|
|
@ -960,7 +885,7 @@ class RelationController extends ControllerBehavior
|
||||||
* Multiple (has many, belongs to many)
|
* Multiple (has many, belongs to many)
|
||||||
*/
|
*/
|
||||||
if ($this->viewMode == 'multi') {
|
if ($this->viewMode == 'multi') {
|
||||||
$config = $this->makeConfig($this->config->list);
|
$config = $this->makeConfigForMode('view', 'list');
|
||||||
$config->model = $this->relationModel;
|
$config->model = $this->relationModel;
|
||||||
$config->alias = $this->alias . 'ViewList';
|
$config->alias = $this->alias . 'ViewList';
|
||||||
$config->showSorting = $this->getConfig('view[showSorting]', true);
|
$config->showSorting = $this->getConfig('view[showSorting]', true);
|
||||||
|
|
@ -1027,7 +952,7 @@ class RelationController extends ControllerBehavior
|
||||||
$this->controller->relationExtendQuery($query, $this->field);
|
$this->controller->relationExtendQuery($query, $this->field);
|
||||||
$this->viewModel = $query->getResults() ?: $this->relationModel;
|
$this->viewModel = $query->getResults() ?: $this->relationModel;
|
||||||
|
|
||||||
$config = $this->makeConfig($this->config->form);
|
$config = $this->makeConfigForMode('view', 'form');
|
||||||
$config->model = $this->viewModel;
|
$config->model = $this->viewModel;
|
||||||
$config->arrayName = class_basename($this->relationModel);
|
$config->arrayName = class_basename($this->relationModel);
|
||||||
$config->context = 'relation';
|
$config->context = 'relation';
|
||||||
|
|
@ -1046,13 +971,14 @@ class RelationController extends ControllerBehavior
|
||||||
/*
|
/*
|
||||||
* Pivot
|
* Pivot
|
||||||
*/
|
*/
|
||||||
if ($this->manageMode == 'pivot' && isset($this->config->list)) {
|
if ($this->manageMode == 'pivot' && isset($this->config->pivot)) {
|
||||||
$config = $this->makeConfig($this->config->list);
|
$config = $this->makeConfigForMode('manage', 'list');
|
||||||
$config->model = $this->relationModel;
|
$config->model = $this->relationModel;
|
||||||
$config->alias = $this->alias . 'ManagePivotList';
|
$config->alias = $this->alias . 'ManagePivotList';
|
||||||
$config->showSetup = false;
|
$config->showSetup = false;
|
||||||
$config->defaultSort = $this->getConfig('pivot[defaultSort]');
|
$config->showSorting = $this->getConfig('manage[showSorting]', false);
|
||||||
$config->recordsPerPage = $this->getConfig('pivot[recordsPerPage]');
|
$config->defaultSort = $this->getConfig('manage[defaultSort]');
|
||||||
|
$config->recordsPerPage = $this->getConfig('manage[recordsPerPage]');
|
||||||
$config->recordOnClick = sprintf(
|
$config->recordOnClick = sprintf(
|
||||||
"$.oc.relationBehavior.clickManagePivotListRecord(:id, '%s', '%s')",
|
"$.oc.relationBehavior.clickManagePivotListRecord(:id, '%s', '%s')",
|
||||||
$this->field,
|
$this->field,
|
||||||
|
|
@ -1079,7 +1005,7 @@ class RelationController extends ControllerBehavior
|
||||||
* List
|
* List
|
||||||
*/
|
*/
|
||||||
elseif ($this->manageMode == 'list' && isset($this->config->list)) {
|
elseif ($this->manageMode == 'list' && isset($this->config->list)) {
|
||||||
$config = $this->makeConfig($this->config->list);
|
$config = $this->makeConfigForMode('manage', 'list');
|
||||||
$config->model = $this->relationModel;
|
$config->model = $this->relationModel;
|
||||||
$config->alias = $this->alias . 'ManageList';
|
$config->alias = $this->alias . 'ManageList';
|
||||||
$config->showSetup = false;
|
$config->showSetup = false;
|
||||||
|
|
@ -1131,7 +1057,7 @@ class RelationController extends ControllerBehavior
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = $this->makeConfig($this->config->form);
|
$config = $this->makeConfigForMode('manage', 'form');
|
||||||
$config->model = $this->relationModel;
|
$config->model = $this->relationModel;
|
||||||
$config->arrayName = class_basename($this->relationModel);
|
$config->arrayName = class_basename($this->relationModel);
|
||||||
$config->context = $context ?: 'relation';
|
$config->context = $context ?: 'relation';
|
||||||
|
|
@ -1179,7 +1105,7 @@ class RelationController extends ControllerBehavior
|
||||||
|
|
||||||
protected function makePivotWidget()
|
protected function makePivotWidget()
|
||||||
{
|
{
|
||||||
$config = $this->makeConfig($this->config->pivot);
|
$config = $this->makeConfigForMode('pivot', 'form');
|
||||||
$config->model = $this->relationModel;
|
$config->model = $this->relationModel;
|
||||||
$config->arrayName = class_basename($this->relationModel);
|
$config->arrayName = class_basename($this->relationModel);
|
||||||
$config->context = 'relation';
|
$config->context = 'relation';
|
||||||
|
|
@ -1189,10 +1115,11 @@ class RelationController extends ControllerBehavior
|
||||||
* Existing record
|
* Existing record
|
||||||
*/
|
*/
|
||||||
if ($this->manageId) {
|
if ($this->manageId) {
|
||||||
$config->model = $this->relationModel->find($this->manageId);
|
$foreignKeyName = $this->relationModel->getQualifiedKeyName();
|
||||||
$config->data = $this->relationObject->newPivotStatementForId($this->manageId)->first();
|
$hydratedModel = $this->relationObject->where($foreignKeyName, $this->manageId)->first();
|
||||||
|
|
||||||
if (!$config->model || !$config->data) {
|
$config->model = $hydratedModel;
|
||||||
|
if (!$config->model) {
|
||||||
throw new ApplicationException(Lang::get('backend::lang.model.not_found', [
|
throw new ApplicationException(Lang::get('backend::lang.model.not_found', [
|
||||||
'class' => get_class($config->model), 'id' => $this->manageId
|
'class' => get_class($config->model), 'id' => $this->manageId
|
||||||
]));
|
]));
|
||||||
|
|
@ -1222,4 +1149,134 @@ class RelationController extends ControllerBehavior
|
||||||
|
|
||||||
return $this->sessionKey = FormHelper::getSessionKey();
|
return $this->sessionKey = FormHelper::getSessionKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Helpers
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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':
|
||||||
|
case 'belongsToMany':
|
||||||
|
return ['create', 'add', 'delete', 'remove'];
|
||||||
|
|
||||||
|
case 'hasOne':
|
||||||
|
case 'belongsTo':
|
||||||
|
return ['create', 'update', 'link', 'delete', 'unlink'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the view mode based on the model relationship type.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function evalViewMode()
|
||||||
|
{
|
||||||
|
if ($this->forceViewMode) {
|
||||||
|
return $this->forceViewMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($this->relationType) {
|
||||||
|
case 'hasMany':
|
||||||
|
case 'belongsToMany':
|
||||||
|
return 'multi';
|
||||||
|
|
||||||
|
case 'hasOne':
|
||||||
|
case 'belongsTo':
|
||||||
|
return 'single';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the management mode based on the relation type and settings.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function evalManageMode()
|
||||||
|
{
|
||||||
|
if ($mode = post(self::PARAM_MODE)) {
|
||||||
|
return $mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->forceManageMode) {
|
||||||
|
return $this->forceManageMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($this->eventTarget) {
|
||||||
|
case 'button-create':
|
||||||
|
case 'button-update':
|
||||||
|
return 'form';
|
||||||
|
|
||||||
|
case 'button-link':
|
||||||
|
return 'list';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($this->relationType) {
|
||||||
|
case 'belongsTo':
|
||||||
|
return 'list';
|
||||||
|
|
||||||
|
case 'belongsToMany':
|
||||||
|
if (isset($this->config->pivot)) return 'pivot';
|
||||||
|
elseif ($this->eventTarget == 'list') return 'form';
|
||||||
|
else return 'list';
|
||||||
|
|
||||||
|
case 'hasOne':
|
||||||
|
case 'hasMany':
|
||||||
|
if ($this->eventTarget == 'button-add') return 'list';
|
||||||
|
else return 'form';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the configuration for a mode (view, manage, pivot) for an
|
||||||
|
* expected type (list, form). Uses fallback configuration.
|
||||||
|
*/
|
||||||
|
protected function makeConfigForMode($mode = 'view', $type = 'list')
|
||||||
|
{
|
||||||
|
$config = null;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for $this->config->view['list']
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
isset($this->config->{$mode}) &&
|
||||||
|
array_key_exists($type, $this->config->{$mode})
|
||||||
|
) {
|
||||||
|
$config = $this->config->{$mode}[$type];
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Look for $this->config->list
|
||||||
|
*/
|
||||||
|
elseif (isset($this->config->{$type})) {
|
||||||
|
$config = $this->config->{$type};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply substitutes:
|
||||||
|
*
|
||||||
|
* - view.list => manage.list
|
||||||
|
*/
|
||||||
|
if (!$config) {
|
||||||
|
|
||||||
|
if ($mode == 'manage' && $type == 'list') {
|
||||||
|
return $this->makeConfigForMode('view', $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ApplicationException('Missing configuration for '.$mode.'.'.$type.' in RelationController definition '.$this->field);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->makeConfig($config);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<!-- Passable fields -->
|
<!-- Passable fields -->
|
||||||
<input type="hidden" name="manage_id" value="<?= $relationManageId ?>" />
|
<input type="hidden" name="manage_id" value="<?= $relationManageId ?>" />
|
||||||
<input type="hidden" name="_relation_field" value="<?= $relationField ?>" />
|
<input type="hidden" name="_relation_field" value="<?= $relationField ?>" />
|
||||||
|
<input type="hidden" name="_relation_mode" value="form" />
|
||||||
<input type="hidden" name="_relation_session_key" value="<?= $relationSessionKey ?>" />
|
<input type="hidden" name="_relation_session_key" value="<?= $relationSessionKey ?>" />
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use Str;
|
||||||
use Input;
|
use Input;
|
||||||
use Validator;
|
use Validator;
|
||||||
use System\Models\File;
|
use System\Models\File;
|
||||||
use SystemException;
|
use ApplicationException;
|
||||||
use Backend\Classes\FormField;
|
use Backend\Classes\FormField;
|
||||||
use Backend\Classes\FormWidgetBase;
|
use Backend\Classes\FormWidgetBase;
|
||||||
use ValidationException;
|
use ValidationException;
|
||||||
|
|
@ -182,6 +182,14 @@ class FileUpload extends FormWidgetBase
|
||||||
protected function getRelationObject()
|
protected function getRelationObject()
|
||||||
{
|
{
|
||||||
list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom);
|
list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom);
|
||||||
|
|
||||||
|
if (!$model->hasRelation($attribute)) {
|
||||||
|
throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [
|
||||||
|
'class' => get_class($model),
|
||||||
|
'relation' => $attribute
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
return $model->{$attribute}();
|
return $model->{$attribute}();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,7 +238,7 @@ class FileUpload extends FormWidgetBase
|
||||||
return $this->makePartial('config_form');
|
return $this->makePartial('config_form');
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new SystemException('Unable to find file, it may no longer exist');
|
throw new ApplicationException('Unable to find file, it may no longer exist');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -248,7 +256,7 @@ class FileUpload extends FormWidgetBase
|
||||||
return ['item' => $file->toArray()];
|
return ['item' => $file->toArray()];
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new SystemException('Unable to find file, it may no longer exist');
|
throw new ApplicationException('Unable to find file, it may no longer exist');
|
||||||
}
|
}
|
||||||
catch (Exception $ex) {
|
catch (Exception $ex) {
|
||||||
return json_encode(['error' => $ex->getMessage()]);
|
return json_encode(['error' => $ex->getMessage()]);
|
||||||
|
|
@ -300,7 +308,7 @@ class FileUpload extends FormWidgetBase
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$uploadedFile->isValid()) {
|
if (!$uploadedFile->isValid()) {
|
||||||
throw new SystemException('File is not valid');
|
throw new ApplicationException('File is not valid');
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileRelation = $this->getRelationObject();
|
$fileRelation = $this->getRelationObject();
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<?php namespace Backend\FormWidgets;
|
<?php namespace Backend\FormWidgets;
|
||||||
|
|
||||||
use Lang;
|
use Lang;
|
||||||
|
use ApplicationException;
|
||||||
use Backend\Classes\FormWidgetBase;
|
use Backend\Classes\FormWidgetBase;
|
||||||
use SystemException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record Finder
|
* Record Finder
|
||||||
|
|
@ -54,16 +54,6 @@ class RecordFinder extends FormWidgetBase
|
||||||
*/
|
*/
|
||||||
protected $defaultAlias = 'recordfinder';
|
protected $defaultAlias = 'recordfinder';
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string Relationship type
|
|
||||||
*/
|
|
||||||
public $relationType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string Relationship name
|
|
||||||
*/
|
|
||||||
public $relationName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Model Relationship model
|
* @var Model Relationship model
|
||||||
*/
|
*/
|
||||||
|
|
@ -91,16 +81,6 @@ class RecordFinder extends FormWidgetBase
|
||||||
'descriptionFrom',
|
'descriptionFrom',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->relationName = $this->valueFrom;
|
|
||||||
$this->relationType = $this->model->getRelationType($this->relationName);
|
|
||||||
|
|
||||||
if (!$this->model->hasRelation($this->relationName)) {
|
|
||||||
throw new SystemException(Lang::get('backend::lang.model.missing_relation', [
|
|
||||||
'class' => get_class($this->model),
|
|
||||||
'relation' => $this->relationName
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (post('recordfinder_flag')) {
|
if (post('recordfinder_flag')) {
|
||||||
$this->listWidget = $this->makeListWidget();
|
$this->listWidget = $this->makeListWidget();
|
||||||
$this->listWidget->bindToController();
|
$this->listWidget->bindToController();
|
||||||
|
|
@ -120,6 +100,36 @@ class RecordFinder extends FormWidgetBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value as a relation object from the model,
|
||||||
|
* supports nesting via HTML array.
|
||||||
|
* @return Relation
|
||||||
|
*/
|
||||||
|
protected function getRelationObject()
|
||||||
|
{
|
||||||
|
list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom);
|
||||||
|
|
||||||
|
if (!$model->hasRelation($attribute)) {
|
||||||
|
throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [
|
||||||
|
'class' => get_class($model),
|
||||||
|
'relation' => $attribute
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $model->{$attribute}();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the model of a relation type,
|
||||||
|
* supports nesting via HTML array.
|
||||||
|
* @return Relation
|
||||||
|
*/
|
||||||
|
protected function getRelationModel()
|
||||||
|
{
|
||||||
|
list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom);
|
||||||
|
return $model->makeRelation($attribute);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
@ -220,7 +230,7 @@ class RecordFinder extends FormWidgetBase
|
||||||
protected function makeListWidget()
|
protected function makeListWidget()
|
||||||
{
|
{
|
||||||
$config = $this->makeConfig($this->getConfig('list'));
|
$config = $this->makeConfig($this->getConfig('list'));
|
||||||
$config->model = $this->model->makeRelation($this->relationName);
|
$config->model = $this->getRelationModel();
|
||||||
$config->alias = $this->alias . 'List';
|
$config->alias = $this->alias . 'List';
|
||||||
$config->showSetup = false;
|
$config->showSetup = false;
|
||||||
$config->showCheckboxes = false;
|
$config->showCheckboxes = false;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php namespace Backend\Traits;
|
||||||
|
|
||||||
|
use Backend\Classes\FormField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form Model Saver Trait
|
||||||
|
*
|
||||||
|
* Special logic for applying form data (usually from postback) and
|
||||||
|
* applying it to a model and its relationships. This is a customized,
|
||||||
|
* safer and simplified version of $model->push().
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* $modelsToSave = $this->prepareModelsToSave($model, [...]);
|
||||||
|
*
|
||||||
|
* foreach ($modelsToSave as $modelToSave) {
|
||||||
|
* $modelToSave->save();
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @package october\backend
|
||||||
|
* @author Alexey Bobkov, Samuel Georges
|
||||||
|
*/
|
||||||
|
|
||||||
|
trait FormModelSaver
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array List of prepared models that require saving.
|
||||||
|
*/
|
||||||
|
protected $modelsToSave = [];
|
||||||
|
|
||||||
|
protected function prepareModelsToSave($model, $saveData)
|
||||||
|
{
|
||||||
|
$this->modelsToSave = [];
|
||||||
|
$this->setModelAttributes($model, $saveData);
|
||||||
|
return $this->modelsToSave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a data collection to a model attributes, relations will also be set.
|
||||||
|
* @param array $saveData Data to save.
|
||||||
|
* @param Model $model Model to save to
|
||||||
|
* @return array The collection of models to save.
|
||||||
|
*/
|
||||||
|
protected function setModelAttributes($model, $saveData)
|
||||||
|
{
|
||||||
|
$this->modelsToSave[] = $model;
|
||||||
|
|
||||||
|
if (!is_array($saveData)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$singularTypes = ['belongsTo', 'hasOne', 'morphOne'];
|
||||||
|
foreach ($saveData as $attribute => $value) {
|
||||||
|
$isNested = $attribute == 'pivot' || (
|
||||||
|
$model->hasRelation($attribute) &&
|
||||||
|
in_array($model->getRelationType($attribute), $singularTypes)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($isNested && is_array($value)) {
|
||||||
|
$this->setModelAttributes($model->{$attribute}, $value);
|
||||||
|
}
|
||||||
|
elseif ($value !== FormField::NO_SAVE_DATA) {
|
||||||
|
$model->{$attribute} = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -660,6 +660,12 @@ class Lists extends WidgetBase
|
||||||
$label = studly_case($name);
|
$label = studly_case($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strpos($name, '[') !== false && strpos($name, ']') !== false) {
|
||||||
|
$config['valueFrom'] = $name;
|
||||||
|
$config['sortable'] = false;
|
||||||
|
$config['searchable'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
$columnType = isset($config['type']) ? $config['type'] : null;
|
$columnType = isset($config['type']) ? $config['type'] : null;
|
||||||
|
|
||||||
$column = new ListColumn($name, $label);
|
$column = new ListColumn($name, $label);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue