%PDF- %PDF-
| Direktori : /home/vacivi36/intranet.vacivitta.com.br/protected/humhub/modules/ui/form/widgets/ |
| Current File : /home/vacivi36/intranet.vacivitta.com.br/protected/humhub/modules/ui/form/widgets/BasePicker.php |
<?php
namespace humhub\modules\ui\form\widgets;
use humhub\components\ActiveRecord;
use Yii;
use yii\base\Model;
use yii\db\ActiveQuery;
use yii\helpers\Html;
use yii\helpers\Url;
/**
* Abstract class for picker form fields.
*
* Subclasses should at least overwrite the following fields:
*
* - $defaultRoute for defining a default search query route
* - $itemClass defines the type of item e.g. User/Space/...
* - $itemKey defines the key attribute used as option values e.g. id/guid
*
* And the following methods:
*
* - getItemText for retrieving the option text for an item
* - getItemImage for retrieving the option image (if required)
*
*
* The json result of a picker search query should return an array of items with the following key/values:
*
* - id: option value (itemKey) (required)
* - text: option text (required)
* - image: option image (optional)
* - priority: used to sort results (optional)
* - disabled: can be used to disable certain items (optional)
* - disabbledText: text describing the reason why the item is disabled (optional)
*
* @package humhub.modules_core.user.widgets
* @since 1.2
* @author buddha
*/
abstract class BasePicker extends JsInputWidget
{
/**
* Defines the javascript picker implementation.
*
* @var string
*/
public $jsWidget = 'ui.picker.Picker';
/**
* Disabled items
*/
public $disabledItems;
/**
* Default route used for search queries.
* This can be overwritten by defining the $url.
*
* @var string
*/
public $defaultRoute;
/**
* Search url used to overwrite the $defaultRoute for a picker isntance.
*
* @var string
*/
public $url;
/**
* Maximum amount of selection items.
*
* @var integer
*/
public $maxSelection = 50;
/**
* Minimum character input before triggering search query.
*
* @var integer
*/
public $minInput = 3;
/**
* Minimum character input before triggering search query.
*
* @var integer
*/
public $maxInput = 20;
/**
* Array of item instances. If this array is set the picker will ignore the
* actual model attribute and instead use this array as selection.
*
* It this array is not set, the picker will try to load the items by means of the
* model attribute
*
* @see BasePickerField::loadItems
* @var array
*/
public $selection;
/**
* @var array Array of item instances used as long the minInput is not exceed.
*/
public $defaultResults = [];
/**
* The item class used to load items by means of the model attribute value.
*
* @var string
*/
public $itemClass;
/**
* The item key used as option value and loading items by attribute value.
* e.g. id or guid.
*
* @since v1.3 'id' by default
*
* @var string
*/
public $itemKey = 'id';
/**
* If the ActiveForm is set, it will be used to create the picker field,
* otherwise it's created by Html::activeDropDownList
*
* @var \yii\widgets\ActiveForm
*/
public $form;
/**
* @deprecated since 1.2.2 use $name instead
*/
public $formName;
/**
* Model instance.
*
* @var \yii\db\ActiveRecord
*/
public $model;
/**
* Model attribute which holds the picker value. The referenced model attribute has to be an
* array.
*
* @var string
*/
public $attribute;
/**
* If set to true, the picker will allow adding new options not included in the current search result.
*
* > Note: New values will be submitted as '_add:term' to distinguish between new and existing options. The filtering and insertion
* has to be handled manually within the submit/form logic.
*
* e.g.:
*
* ```php
* foreach($values as $value) {
* if(strpos($value, '_add:') === 0) {
* $newValue = substr($value, strlen('_add:'));
* // Save new item with newValue
* } else {
* $item = MyItem::findOne((int) $value);
* // ...
* }
* }
* ```
*
* @var bool|null
*/
public $addOptions = false;
/**
* Can be used to overwrite the default placeholder.
* @var string
*/
public $placeholder;
/**
* Can be used to overwrite the default add more placeholder.
* @var string
*/
public $placeholderMore;
/**
* If set to true the picker will be focused automatically.
*
* @var boolean
*/
public $focus = false;
/**
* @inheritdoc
* @var boolean
*/
public $init = true;
/**
* Used to retrieve the option text of a given $item.
*
* @param \yii\db\ActiveRecord $item selected item
* @return string item option text
*/
protected abstract function getItemText($item);
/**
* Used to retrieve the option image url of a given $item.
*
* @param \yii\db\ActiveRecord $item selected item
* @return string|null image url or null if no selection image required.
*/
protected abstract function getItemImage($item);
/**
* @inhertidoc
*/
public function beforeRun()
{
//Only for compatibility
if (empty($this->name)) {
$this->name = $this->formName;
}
return parent::beforeRun();
}
/**
* @inhertidoc
*/
public function run()
{
if ($this->selection != null && !is_array($this->selection)) {
$this->selection = [$this->selection];
}
// Prepare current selection and selection options
$selection = [];
$selectedOptions = $this->getSelectedOptions();
foreach ($selectedOptions as $id => $option) {
$selection[$id] = $option['data-text'];
}
$options = $this->getOptions();
$options['options'] = $selectedOptions;
if ($this->form != null) {
return $this->form->field($this->model, $this->attribute)->dropDownList($selection, $options);
} elseif ($this->model != null) {
return Html::activeDropDownList($this->model, $this->attribute, $selection, $options);
} else {
$name = (!$this->name) ? 'pickerField' : $this->name;
return Html::dropDownList($name, $this->value, $selection, $options);
}
}
/**
* Prepares the selected options either by using the $selection array or by loading the items
* by means of the model attribute value.
*
* The resulting array has the following format:
*
* [itemKey] => [
* 'data-text' => itemText
* 'data-image' => itemImage
* 'selected' => selected
* ]
*
* Subclasses should overwrite the getItemText and getItemImage function for this purpose.
*
* @return array
*/
protected function getSelectedOptions()
{
if (!$this->selection && $this->model != null) {
$attribute = $this->attribute;
if (strrpos($attribute, '[') !== false) {
$this->selection = $this->loadItems(Html::getAttributeValue($this->model, $attribute));
} else {
$this->selection = $this->loadItems($this->model->$attribute);
}
}
if (!$this->selection) {
$this->selection = [];
}
$result = [];
foreach ($this->selection as $item) {
if (!$item) {
continue;
}
$result[$this->getItemKey($item)] = $this->buildItemOption($item);
}
return $result;
}
/**
* Responsible for building the option data for an item.
*
* @param mixed $item
* @param boolean $selected
* @return array
*/
protected function buildItemOption($item, $selected = true)
{
$result = [
'data-id' => $this->getItemKey($item),
'data-text' => $this->getItemText($item),
'data-image' => $this->getItemImage($item),
];
if ($selected) {
$result['selected'] = 'selected';
}
return $result;
}
/**
* Returns the item key which is used as option value. By default we use
* the $itemKey attribibute of $item.
*
* e.g. $itemKey = 'id'
*
* @param mixed $item
* @return string
*/
protected function getItemKey($item)
{
$itemKey = $this->itemKey;
return $item->$itemKey;
}
/**
* Loads all items of the given $selection array.
* The $selection array contains all selected itemKeys.
*
* @param array|string $selection array of itemKeys or comma separated string
* @return array of items of type $itemClass or empty array for an empty selection
*/
public function loadItems($selection = null)
{
if (empty($selection)) {
return [];
}
if ($selection instanceof ActiveQuery) {
return $selection->all();
}
// For older version (prior 1.2) - try to convert comma separated list to array
if (!is_array($selection)) {
$selection = explode(',', $selection);
}
$itemClass = $this->itemClass;
return $itemClass::find()->where([$this->itemKey => $selection])->all();
}
/**
* @inheritdoc
*/
protected function getAttributes()
{
return [
'multiple' => 'multiple',
'data-multiple' => 'true',
'data-tags' => 'true',
'size' => '1',
'class' => 'form-control',
'style' => 'width:100%',
'title' => $this->placeholder
];
}
/**
* Returns an array of data attributes for this picker isntance.
* Following data attributes can be configured by default:
*
* - data-placeholder: Placeholder text if no value is set.
* - data-placeholder-more: Placeholder text displayed if at least one item is set.
* - data-maximum-selected: Info message displayed if $maxSelection is exceed.
* - data-no-result: Empty result message.
* - data-format-ajax-error: Ajax error message.
* - data-load-more: Load more items text.
* - data-input-too-short: Info message displayed if $minInput characters is not exceed.
* - data-input-too-long: Info message displayed if $maxInput characters is exceed.
*
* @return array
*/
protected function getData()
{
$allowMultiple = $this->maxSelection !== 1;
$placeholder = ($this->placeholder != null) ? $this->placeholder : Yii::t('UserModule.chooser', 'Select {n,plural,=1{item} other{items}}', ['n' => ($allowMultiple) ? 2 : 1]);
$placeholderMore = ($this->placeholderMore != null) ? $this->placeholderMore : Yii::t('UserModule.chooser', 'Select...');
$result = [
'add-options' => $this->addOptions,
'picker-url' => $this->getUrl(),
'picker-focus' => $this->focus,
'maximum-selection-length' => $this->maxSelection,
'maximum-input-length' => $this->maxInput,
'minimum-input-length' => $this->minInput,
'placeholder' => $placeholder,
'placeholder-more' => $placeholderMore,
'no-result' => Yii::t('UserModule.chooser', 'Your search returned no matches.'),
'format-ajax-error' => Yii::t('UserModule.chooser', 'An unexpected error occurred while loading the result.'),
'load-more' => Yii::t('UserModule.chooser', 'Load more'),
'input-too-short' => Yii::t('UserModule.chooser', 'Please enter at least {n} character', ['n' => $this->minInput]),
'input-too-long' => Yii::t('UserModule.chooser', 'You reached the maximum number of allowed characters ({n}).', ['n' => $this->maxInput]),
'default-results' => $this->getDefaultResultData()
];
if(!empty($this->disabledItems)) {
$result['disabled-items'] = $this->disabledItems;
}
if ($this->maxSelection) {
$result['maximum-selected'] = Yii::t('UserModule.chooser', 'This field only allows a maximum of {n,plural,=1{# item} other{# items}}.', ['n' => $this->maxSelection]);
}
return $result;
}
protected function getDefaultResultData()
{
$result = [];
foreach ($this->defaultResults as $item) {
$result[] = $this->buildItemOption($item);
}
return $result;
}
/**
* Returns the url for this picker instance. If no $url is set we use the $defaultRoute for creating the url.
*
* @return string
*/
protected function getUrl()
{
return ($this->url) ? $this->url : Url::to([$this->defaultRoute]);
}
}