189 lines
5.4 KiB
PHP
Raw Normal View History

2014-05-14 23:24:20 +10:00
<?php namespace Backend\FormWidgets;
use Db;
use Backend\Classes\FormField;
2014-05-14 23:24:20 +10:00
use Backend\Classes\FormWidgetBase;
use October\Rain\Database\Relations\Relation as RelationBase;
2014-05-14 23:24:20 +10:00
/**
* Form Relationship
* Renders a field prepopulated with a belongsTo and belongsToHasMany relation.
*
* @package october\backend
* @author Alexey Bobkov, Samuel Georges
*/
class Relation extends FormWidgetBase
{
use \Backend\Traits\FormModelWidget;
//
// Configurable properties
//
2014-05-14 23:24:20 +10:00
/**
* @var string Model column to use for the name reference
2014-05-14 23:24:20 +10:00
*/
public $nameFrom = 'name';
2014-05-14 23:24:20 +10:00
/**
* @var string Custom SQL column selection to use for the name reference
*/
public $sqlSelect;
2014-05-14 23:24:20 +10:00
/**
* @var string Empty value to use if the relation is singluar (belongsTo)
2014-05-14 23:24:20 +10:00
*/
public $emptyOption;
/**
* @var string Use a custom scope method for the list query.
*/
public $scope;
/**
* @var string Define the order of the list query.
*/
public $order;
//
// Object properties
//
2014-05-14 23:24:20 +10:00
/**
2017-03-16 06:26:14 +11:00
* @inheritDoc
2014-05-14 23:24:20 +10:00
*/
protected $defaultAlias = 'relation';
2014-05-14 23:24:20 +10:00
/**
* @var FormField Object used for rendering a simple field type
*/
public $renderFormField;
2014-05-14 23:24:20 +10:00
/**
2017-03-16 06:26:14 +11:00
* @inheritDoc
2014-05-14 23:24:20 +10:00
*/
public function init()
{
$this->fillFromConfig([
'nameFrom',
'emptyOption',
'scope',
'order',
]);
if (isset($this->config->select)) {
$this->sqlSelect = $this->config->select;
}
2014-05-14 23:24:20 +10:00
}
/**
2017-03-16 06:26:14 +11:00
* @inheritDoc
2014-05-14 23:24:20 +10:00
*/
public function render()
{
$this->prepareVars();
return $this->makePartial('relation');
}
/**
* Prepares the view data
*/
public function prepareVars()
{
$this->vars['field'] = $this->makeRenderFormField();
}
/**
* Makes the form object used for rendering a simple field type
*/
protected function makeRenderFormField()
{
2014-10-10 23:50:05 +02:00
return $this->renderFormField = RelationBase::noConstraints(function () {
$field = clone $this->formField;
$relationObject = $this->getRelationObject();
$query = $relationObject->newQuery();
list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom);
$relationType = $model->getRelationType($attribute);
$relationModel = $model->makeRelation($attribute);
if (in_array($relationType, ['belongsToMany', 'morphToMany', 'morphedByMany', 'hasMany'])) {
$field->type = 'checkboxlist';
}
elseif (in_array($relationType, ['belongsTo', 'hasOne'])) {
$field->type = 'dropdown';
}
// Order query by the configured option.
if ($this->order) {
// Using "raw" to allow authors to use a string to define the order clause.
$query->orderByRaw($this->order);
}
2014-10-10 23:50:05 +02:00
// It is safe to assume that if the model and related model are of
// the exact same class, then it cannot be related to itself
if ($model->exists && (get_class($model) == get_class($relationModel))) {
$query->where($relationModel->getKeyName(), '<>', $model->getKey());
}
// Even though "no constraints" is applied, belongsToMany constrains the query
// by joining its pivot table. Remove all joins from the query.
$query->getQuery()->getQuery()->joins = [];
if ($scopeMethod = $this->scope) {
$query->$scopeMethod($model);
}
// Determine if the model uses a tree trait
$treeTraits = ['October\Rain\Database\Traits\NestedTree', 'October\Rain\Database\Traits\SimpleTree'];
$usesTree = count(array_intersect($treeTraits, class_uses($relationModel))) > 0;
// The "sqlSelect" config takes precedence over "nameFrom".
// A virtual column called "selection" will contain the result.
// Tree models must select all columns to return parent columns, etc.
if ($this->sqlSelect) {
$nameFrom = 'selection';
$selectColumn = $usesTree ? '*' : $relationModel->getKeyName();
$result = $query->select($selectColumn, Db::raw($this->sqlSelect . ' AS ' . $nameFrom));
}
else {
$nameFrom = $this->nameFrom;
$result = $query->getQuery()->get();
}
// Some simpler relations can specify a custom local or foreign "other" key,
// which can be detected and implemented here automagically.
$primaryKeyName = in_array($relationType, ['hasMany', 'belongsTo', 'hasOne'])
? $relationObject->getOtherKey()
: $relationModel->getKeyName();
$field->options = $usesTree
? $result->listsNested($nameFrom, $primaryKeyName)
: $result->lists($nameFrom, $primaryKeyName);
return $field;
});
2014-05-14 23:24:20 +10:00
}
/**
2017-03-16 06:26:14 +11:00
* @inheritDoc
*/
2015-01-05 09:43:39 +11:00
public function getSaveValue($value)
{
if ($this->formField->disabled || $this->formField->hidden) {
return FormField::NO_SAVE_DATA;
}
2014-10-10 23:50:05 +02:00
if (is_string($value) && !strlen($value)) {
2014-05-29 19:35:46 +10:00
return null;
2014-10-10 23:50:05 +02:00
}
2014-05-29 19:35:46 +10:00
2014-10-10 23:50:05 +02:00
if (is_array($value) && !count($value)) {
2014-05-29 19:35:46 +10:00
return null;
2014-10-10 23:50:05 +02:00
}
2014-05-29 19:35:46 +10:00
return $value;
}
2014-10-10 23:50:05 +02:00
}