/** * @param \yii\db\ActiveRecord $model * @param string $relation * @param \yii\db\ActiveQuery $activeRelation * @param bool|false $multiple * * @return array * @throws Exception * @throws InvalidConfigException */ public static function getRelationWidgetOptions($model, $relation, $activeRelation, $multiple = false) { /** @var \netis\crud\db\ActiveRecord $relModel */ $relModel = new $activeRelation->modelClass(); list($createRoute, $searchRoute, $indexRoute) = FormBuilder::getRelationRoutes($model, $relModel, $activeRelation); if ($indexRoute === null) { return self::getRelationWidgetStaticOptions($model, $relation, $activeRelation, $multiple); } $isMany = $activeRelation->multiple; $foreignKeys = array_values($activeRelation->link); $foreignKey = reset($foreignKeys); $dbColumns = $model->getTableSchema()->columns; $primaryKey = $relModel::primaryKey(); if (($labelAttributes = $relModel->getBehavior('labels')->attributes) !== null) { $fields = array_merge($primaryKey, $labelAttributes); } else { $fields = $primaryKey; } $value = self::getRelationValue($model, $relation, $activeRelation); $allowClear = $multiple || $isMany ? true : !$model->isAttributeRequired($foreignKey) && (!isset($dbColumns[$foreignKey]) || $dbColumns[$foreignKey]->allowNull); $jsPrimaryKey = json_encode($primaryKey); $jsSeparator = \netis\crud\crud\Action::COMPOSITE_KEY_SEPARATOR; $jsId = <<<JavaScript function(object){ var keys = {$jsPrimaryKey}, values = []; for (var i = 0; i < keys.length; i++) { values.push(object[keys[i]]); } return netis.implodeEscaped('{$jsSeparator}', values); } JavaScript; // check if only one option is available and if yes - set it as selected value if (!$allowClear && trim($value) === '') { $checkedRelations = $relModel->getCheckedRelations(Yii::$app->user->id, $activeRelation->modelClass . '.read'); $relQuery = $relModel::find()->select($primaryKey)->from($relModel::tableName() . ' t')->authorized($relModel, $checkedRelations, Yii::$app->user->getIdentity())->asArray(); if ($relQuery->count() === 1) { $value = $relQuery->one(); $value = Action::implodeEscaped(Action::KEYS_SEPARATOR, $value); } } $label = null; if ($model instanceof \netis\crud\db\ActiveRecord) { $label = $model->getRelationLabel($activeRelation, Html::getAttributeName($relation)); } $ajaxResults = new JsExpression('s2helper.results'); $clientEvents = null; if ($indexRoute !== null && ($searchRoute !== null || $createRoute !== null)) { list($ajaxResults, $clientEvents) = self::getRelationAjaxOptions($searchRoute, $createRoute, $jsPrimaryKey, $label, $relation); } //we get prefix from $relation because it could be in format [3]relation and we need to have [3]foreign_key here $relationName = Html::getAttributeName($relation); $prefixedFk = str_replace($relation, $foreignKey, $relationName); return ['class' => 'maddoger\\widgets\\Select2', 'model' => $model, 'attribute' => $isMany ? $relation : $prefixedFk, 'clientOptions' => array_merge(['formatResult' => new JsExpression('s2helper.formatResult'), 'formatSelection' => new JsExpression('s2helper.formatSelection'), 'id' => new JsExpression($jsId), 'width' => '100%', 'allowClear' => $allowClear, 'closeOnSelect' => true, 'initSelection' => new JsExpression($multiple ? 's2helper.initMulti' : 's2helper.initSingle'), 'ajax' => ['url' => Url::toRoute(array_merge($indexRoute, ['_format' => 'json', 'fields' => implode(',', $fields)])), 'dataFormat' => 'json', 'quietMillis' => 300, 'data' => new JsExpression('s2helper.data'), 'results' => $ajaxResults]], $multiple ? ['multiple' => true] : []), 'clientEvents' => $clientEvents, 'options' => ['class' => 'select2', 'value' => $value, 'placeholder' => self::getPrompt(), 'data-relation-pk' => count($primaryKey) === 1 ? reset($primaryKey) : null]]; }
/** * @param string $relationName * @param array $relation an item obtained from getModelRelations() result array, * @param \netis\crud\db\ActiveRecord $model * @return array */ private function getRelationButtons($relationName, $relation, $model) { /** @var \netis\crud\db\ActiveRecord $relatedModel */ $relatedModel = $relation['model']; $dataProvider = $relation['dataProvider']; list($createRoute, $searchRoute, $indexRoute) = FormBuilder::getRelationRoutes($model, $relatedModel, $dataProvider->query); $result = []; if ($createRoute !== null) { $result[self::CREATE_RELATED_BUTTON] = Html::a('<span class="glyphicon glyphicon-file"></span>', '#', ['title' => Yii::t('app', 'Create new'), 'aria-label' => Yii::t('app', 'Create new'), 'data-pjax' => '0', 'data-toggle' => 'modal', 'data-target' => '#relationModal', 'data-relation' => $relationName, 'data-title' => $relatedModel->getCrudLabel('create'), 'data-pjax-url' => Url::toRoute($createRoute), 'data-mode' => FormBuilder::MODAL_MODE_NEW_RECORD, 'class' => 'btn btn-default', 'id' => 'createRelation-' . $relationName]); } else { // a normal submit button that tries to save the record // and open the usual modal immediately after reloading the page $result[self::CREATE_RELATED_BUTTON] = Html::button('<span class="glyphicon glyphicon-file"></span>', ['name' => self::NEW_RELATED_BUTTON_NAME, 'type' => 'submit', 'class' => 'btn btn-default', 'value' => $relationName]); } if ($searchRoute !== null) { $result[self::SEARCH_RELATED_BUTTON] = Html::a('<span class="glyphicon glyphicon-plus"></span>', '#', ['title' => Yii::t('app', 'Add existing'), 'aria-label' => Yii::t('app', 'Add existing'), 'data-pjax' => '0', 'data-toggle' => 'modal', 'data-target' => '#relationModal', 'data-relation' => $relationName, 'data-title' => $relatedModel->getCrudLabel('index'), 'data-pjax-url' => Url::toRoute($searchRoute), 'data-mode' => FormBuilder::MODAL_MODE_EXISTING_RECORD, 'class' => 'btn btn-default']); } return $result; }