2014-10-10 23:50:05 +02:00

155 lines
4.5 KiB
PHP

<?php namespace Backend\FormWidgets;
use Lang;
use Backend\Classes\FormWidgetBase;
use System\Classes\SystemException;
use Illuminate\Database\Eloquent\Relations\Relation as RelationBase;
/**
* Form Relationship
* Renders a field prepopulated with a belongsTo and belongsToHasMany relation.
*
* @package october\backend
* @author Alexey Bobkov, Samuel Georges
*/
class Relation extends FormWidgetBase
{
/**
* {@inheritDoc}
*/
public $defaultAlias = 'relation';
/**
* @var string Relationship type
*/
public $relationType;
/**
* @var string Relationship name
*/
public $relationName;
/**
* @var FormField Object used for rendering a simple field type
*/
public $renderFormField;
/**
* @var string Model column to use for the name reference
*/
public $nameFrom = 'name';
/**
* @var string Model column to use for the description reference
*/
public $descriptionFrom = 'description';
/**
* @var string Empty value to use if the relation is singluar (belongsTo)
*/
public $emptyOption;
/**
* {@inheritDoc}
*/
public function init()
{
$this->relationName = $this->valueFrom;
$this->relationType = $this->model->getRelationType($this->relationName);
$this->nameFrom = $this->getConfig('nameFrom', $this->nameFrom);
$this->descriptionFrom = $this->getConfig('descriptionFrom', $this->descriptionFrom);
$this->emptyOption = $this->getConfig('emptyOption');
/* @todo Remove lines if year >= 2015 */
if ($this->getConfig('nameColumn')) {
$this->nameFrom = $this->getConfig('nameColumn');
}
/* @todo Remove lines if year >= 2015 */
if ($this->getConfig('descriptionColumn')) {
$this->descriptionFrom = $this->getConfig('descriptionColumn');
}
if (!$this->model->hasRelation($this->relationName)) {
throw new SystemException(Lang::get(
'backend::lang.model.missing_relation',
['class'=>get_class($this->controller), 'relation'=>$this->relationName]
));
}
}
/**
* {@inheritDoc}
*/
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()
{
return $this->renderFormField = RelationBase::noConstraints(function () {
$field = clone $this->formField;
list($model, $attribute) = $this->getModelArrayAttribute($this->relationName);
$relatedObj = $model->makeRelation($attribute);
$query = $model->{$attribute}()->newQuery();
if (in_array($this->relationType, ['belongsToMany', 'morphToMany', 'morphedByMany'])) {
$field->type = 'checkboxlist';
} elseif ($this->relationType == 'belongsTo') {
$field->type = 'dropdown';
$field->placeholder = $this->emptyOption;
}
// 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($relatedObj))) {
$query->where($relatedObj->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 = [];
$treeTraits = ['October\Rain\Database\Traits\NestedTree', 'October\Rain\Database\Traits\SimpleTree'];
if (count(array_intersect($treeTraits, class_uses($relatedObj))) > 0) {
$field->options = $query->listsNested($this->nameFrom, $relatedObj->getKeyName());
} else {
$field->options = $query->lists($this->nameFrom, $relatedObj->getKeyName());
}
return $field;
});
}
/**
* {@inheritDoc}
*/
public function getSaveData($value)
{
if (is_string($value) && !strlen($value)) {
return null;
}
if (is_array($value) && !count($value)) {
return null;
}
return $value;
}
}