/** * Retrieves form fields configuration. Fields can be config arrays, ActiveField objects or closures. * * @param \yii\base\Model|\netis\crud\db\ActiveRecord $model * @param array $fields * @param bool $multiple true for multiple values inputs, usually used for search forms * @param array $hiddenAttributes list of attribute names to render as hidden fields * * @return array form fields * @throws InvalidConfigException */ public static function getFormFields($model, $fields, $multiple = false, $hiddenAttributes = []) { if (!$model instanceof \yii\db\ActiveRecord) { return $model->safeAttributes(); } $keys = Action::getModelKeys($model); $hiddenAttributes = array_flip($hiddenAttributes); list($behaviorAttributes, $blameableAttributes) = Action::getModelBehaviorAttributes($model); $attributes = $model->safeAttributes(); $relations = $model->relations(); if (($versionAttribute = $model->optimisticLock()) !== null) { $hiddenAttributes[$versionAttribute] = true; } $formFields = []; foreach ($fields as $key => $field) { if ($field instanceof ActiveField) { $formFields[$key] = $field; continue; } elseif (!is_string($field) && is_callable($field)) { $formFields[$key] = call_user_func($field, $model); if (!is_string($formFields[$key])) { throw new InvalidConfigException('Field definition must be either an ActiveField or a callable.'); } continue; } elseif (!is_string($field)) { throw new InvalidConfigException('Field definition must be either an ActiveField or a callable.'); } $attributeName = Html::getAttributeName($field); if (in_array($attributeName, $relations)) { $formFields = static::addRelationField($formFields, $model, $field, $hiddenAttributes, $attributes, $multiple); } elseif (in_array($attributeName, $attributes)) { if (in_array($attributeName, $keys) || in_array($attributeName, $behaviorAttributes)) { continue; } $formFields = static::addFormField($formFields, $model, $field, $hiddenAttributes, $multiple); } } return $formFields; }
/** * Retrieves grid columns configuration using the modelClass. * @param Model $model * @param array $fields * @return array grid columns */ public function getIndexGridColumns($model, $fields) { $id = Yii::$app->request->getQueryParam('id'); $relationName = Yii::$app->request->getQueryParam('relation'); $multiple = Yii::$app->request->getQueryParam('multiple', 'true') === 'true'; foreach ($fields as $key => $field) { if ((is_array($field) || !is_string($field) && is_callable($field)) && $key === $relationName || $field === $relationName) { unset($fields[$key]); } } return array_merge([['class' => 'yii\\grid\\CheckboxColumn', 'multiple' => $multiple, 'headerOptions' => ['class' => 'column-serial'], 'checkboxOptions' => function ($model, $key, $index, $column) use($id, $relationName) { /** @var \yii\db\ActiveRecord $model */ $options = ['value' => is_array($key) ? json_encode($key, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : $key]; if (empty($relationName) || $model->{$relationName} === null || trim($id) === '') { return $options; } $relation = $model->getRelation($relationName); if ($relation->multiple) { /** @var \yii\db\ActiveRecord $relationClass */ $relationClass = $relation->modelClass; if (Action::importKey($relationClass::primaryKey(), $id) === $model->getAttributes(array_keys($relation->link))) { $options['checked'] = true; $options['disabled'] = true; } } elseif (Action::exportKey($relation->one()->getPrimaryKey()) === $id) { $options['checked'] = true; $options['disabled'] = true; } return $options; }], ['class' => 'yii\\grid\\SerialColumn', 'headerOptions' => ['class' => 'column-serial']]], self::getGridColumns($model, $fields)); }
/** * Processes a filter form and row selection submitted via GET into a CDbCriteria object. * @param \yii\db\ActiveRecord $model * @return Query */ public function getQuery($model) { $query = clone parent::getQuery($model); $primaryKey = array_map(function ($column) { return 't.' . $column; }, $model::primaryKey()); return $query->andWhere(['in', $primaryKey, self::importKey($primaryKey, \Yii::$app->request->getQueryParam('keys'))]); }
/** * Retrieves grid columns configuration using the modelClass. * @param Model $model * @param string $fields * @param string $relationName * @param \yii\db\ActiveQuery $relation * @return array grid columns */ public static function getRelationGridColumns($model, $fields, $relationName, $relation) { $columns = parent::getRelationGridColumns($model, $fields, $relationName, $relation); $controller = Yii::$app->crudModelsMap[$model::className()]; $actionColumn = new \yii\grid\ActionColumn(); if (!isset($columns[0]) || !isset($columns[0]['class']) || $columns[0]['class'] !== 'yii\\grid\\ActionColumn') { array_unshift($columns, ['class' => 'yii\\grid\\ActionColumn', 'headerOptions' => ['class' => 'column-action'], 'controller' => $controller, 'template' => '', 'buttons' => []]); } $columns[0]['template'] = '{update} {unlink}'; $columns[0]['urlCreator'] = function ($action, $model, $key, $index) use($controller, $relation) { $params = is_array($key) ? $key : ['id' => (string) $key]; if ($action === 'update') { $params['hide'] = implode(',', array_keys($relation->link)); } $params[0] = $controller . '/' . $action; return Url::toRoute($params); }; $columns[0]['buttons']['update'] = function ($url, $model, $key) use($actionColumn, $relationName) { /** @var \netis\crud\db\ActiveRecord $model */ if (!Yii::$app->user->can($model::className() . '.update', ['model' => $model])) { return null; } $options = array_merge(['title' => Yii::t('app', 'Update'), 'aria-label' => Yii::t('app', 'Update'), 'data-pjax' => '0', 'data-toggle' => 'modal', 'data-target' => '#relationModal', 'data-relation' => $relationName, 'data-title' => $model->getCrudLabel('update'), 'data-pjax-url' => $url, 'class' => 'btn btn-default btn-xs'], $actionColumn->buttonOptions); return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, $options); }; /** @var \yii\db\ActiveQuery $relation */ $remove = false; $modelClass = $relation->modelClass; foreach (array_keys($relation->link) as $foreignKey) { $remove = $remove || !$modelClass::getTableSchema()->getColumn($foreignKey)->allowNull; } $columns[0]['buttons']['unlink'] = function ($url, $model, $key) use($actionColumn, $remove) { /** @var \netis\crud\db\ActiveRecord $model */ if (!Yii::$app->user->can($model::className() . ($remove ? '.delete' : '.update'), ['model' => $model])) { return null; } $options = array_merge(['title' => Yii::t('app', 'Unlink'), 'aria-label' => Yii::t('app', 'Unlink'), 'data-pjax' => '0', 'class' => 'remove btn btn-default btn-xs'], $actionColumn->buttonOptions); return Html::a('<span class="glyphicon glyphicon-remove"></span>', $url, $options); }; return $columns; }
" role="tab" data-toggle="tab"> <?php echo $model->getRelationLabel($data['dataProvider']->query, $relationName); ?> </a> </li> <?php } ?> </ul> <div class="tab-content"> <?php foreach ($relations as $relationName => $data) { echo Html::beginTag('div', ['role' => 'tabpanel', 'id' => 'tab_' . $relationName, 'class' => 'tab-pane fade' . ($relationName === $activeRelation ? ' in active' : '')]); if (!isset($renderKeyInputs) || $renderKeyInputs) { /** @var \yii\db\ActiveRecord $relationModel */ $relationModel = $data['model']; /** @var \yii\db\ActiveQuery $query */ $query = clone $data['dataProvider']->query; $keys = Action::implodeEscaped(Action::KEYS_SEPARATOR, array_map('\\netis\\crud\\crud\\Action::exportKey', $query->select($relationModel->getTableSchema()->primaryKey)->asArray()->all())); echo Html::activeHiddenInput($model, $relationName . '[add]', ['value' => $keys]); echo Html::activeHiddenInput($model, $relationName . '[remove]'); } echo $this->render('_relation_widget', ['model' => $model, 'relations' => $relations, 'relationName' => $relationName, 'isActive' => $relationName === $activeRelation], $this->context); echo Html::endTag('div'); } ?> </div> </div>
/** * @inheritdoc */ protected static function getAttributeColumn($model, $field, $format) { /** @var LabelsBehavior $behavior */ $behavior = $model->getBehavior('labels'); if (in_array($field, $behavior->attributes)) { return array_merge(parent::getAttributeColumn($model, $field, ['crudLink', [], 'view', function ($value) use($field) { return Html::encode($value->{$field}); }]), ['value' => function ($model, $key, $index, $column) { return $model; }]); } return parent::getAttributeColumn($model, $field, $format); }
use yii\helpers\Html; use yii\helpers\Url; /* @var $this yii\web\View */ /* @var $model netis\crud\db\ActiveRecord */ /* @var mixed $sourceState */ /* @var mixed $targetState */ /* @var array $states */ /* @var $controller netis\crud\crud\ActiveController */ $controller = $this->context; $this->title = $model->getCrudLabel('update') . ': ' . $model->__toString(); $this->params['breadcrumbs'] = $controller->getBreadcrumbs($controller->action, $model); $this->params['menu'] = $controller->getMenu($controller->action, $model); $format = $model->getAttributeFormat($model->getStateAttributeName()); $confirmUrl = Url::toRoute([$action->id, 'id' => \netis\crud\crud\Action::exportKey($model->getPrimaryKey(true)), 'targetState' => $targetState, 'confirmed' => 1]); $cancelUrl = Url::toRoute([isset($_GET['return']) ? $_GET['return'] : $controller->action->viewAction, 'id' => \netis\crud\crud\Action::exportKey($model->getPrimaryKey(true))]); ?> <?php echo Yii::t('netis/fsm/app', 'Change status from {source} to {target}', ['source' => '<span class="badge badge-default">' . Yii::$app->formatter->format($sourceState, $format) . '</span>', 'target' => '<span class="badge badge-primary">' . Yii::$app->formatter->format($targetState, $format) . '</span>']); ?> <?php echo netis\crud\web\Alerts::widget(); ?> <div class="form"> <?php echo Html::label(Yii::t('netis/fsm/app', 'Reason'), 'reason'); ?> <div class="row">
/** * Formats the value as a link to a matching controller. * @param Model|Model[] $value the value to be formatted. * @param array $options the tag options in terms of name-value pairs. See [[Html::a()]]. * @param string $action name of the action to link to * @param string|callable $label if not null, will be used instead of casting the value to string, should be encoded * @return string the formatted result. */ public function asCrudLink($value, $options = [], $action = 'view', $label = null) { if ($value === null || is_array($value) && empty($value)) { return $this->nullDisplay; } $values = is_array($value) ? $value : [$value]; $route = false; $result = []; foreach ($values as $value) { if ($label === null) { $labelString = Html::encode((string) $value); } elseif (is_callable($label)) { $labelString = call_user_func($label, $value); } else { $labelString = $label; } if (!$value instanceof ActiveRecord) { $result[] = $labelString; continue; } if ($route === false) { $route = Yii::$app->crudModelsMap[$value::className()]; } if ($route === null || !Yii::$app->user->can($value::className() . '.read', ['model' => $value])) { $result[] = $labelString; continue; } $result[] = Html::a($labelString, [$route . '/' . $action, 'id' => Action::exportKey($value->getPrimaryKey())], $options); } return implode(', ', $result); }
/** * @return ActiveSearchInterface|ActiveRecord */ public function getSearchModel() { /** @var ActiveRecord $model */ if ($this->controller instanceof ActiveController) { $model = $this->controller->getSearchModel(); } else { $model = new $this->modelClass(); } $params = Yii::$app->request->queryParams; $scope = $model->formName(); if ($scope === '' && is_array($params) || $scope !== '' && isset($params[$scope]) && is_array($params[$scope])) { $model->load($params); } if (isset($params['ids'])) { $keys = Action::importKey($model::primaryKey(), Action::explodeKeys($params['ids'])); $model->setAttributes($keys); } return $model; }
/** * Reads relations information from data sent by end user and uses it to link records to current model. * This is an equivalent to load() and save() methods. * * The data to be loaded is `$data[formName]`, where `formName` refers to the value of [[formName()]]. * If [[formName()]] is empty, the whole `$data` array will be used. * Keys should be relation names. Values are either: * - numeric arrays containing primary key values; * - associative array with keys: 'add', 'remove'. * Warning! Data will NOT be filtered or validated in any way. * @param array $data the data array. This is usually `$_POST` or `$_GET`, but can also be any valid array * supplied by end user. * @param string $formName the form name to be used for loading the data into the model. * If not set, [[formName()]] will be used. * @return bool whether no data was sent or the relations has been successfully linked. * @throws ForbiddenHttpException * @throws \yii\base\InvalidConfigException */ public function saveRelations($data, $formName = null) { /** @var \yii\db\ActiveRecord $owner */ $owner = $this->owner; $scope = $formName === null ? $owner->formName() : $formName; if ($scope !== '') { $data = isset($data[$scope]) ? $data[$scope] : []; } foreach ($data as $relationName => $keys) { if (($relation = $owner->getRelation($relationName, false)) === null) { continue; } if (is_string($keys) && trim($keys) === '') { continue; } if (!is_array($keys) || isset($keys[0])) { $keys = is_array($keys) ? $keys : Action::explodeKeys($keys); $addKeys = Action::importKey($owner::primaryKey(), $keys); $removeKeys = null; } elseif (is_array($keys) && isset($keys['add']) && isset($keys['remove'])) { $addKeys = Action::importKey($owner::primaryKey(), Action::explodeKeys($keys['add'])); $removeKeys = Action::importKey($owner::primaryKey(), Action::explodeKeys($keys['remove'])); } else { throw new InvalidCallException('Relation keys must be either a string, a numeric array or an array with \'add\' and \'remove\' keys.'); continue; } $this->linkByKeys($relation, $addKeys, $removeKeys); } return true; }
echo netis\crud\web\Alerts::widget(); ?> <?php if ($targetState === null && is_array($states)) { ?> <?php foreach ($states as $state) { if (!$state['enabled']) { continue; } echo Html::a('<i class="fa fa-' . $state['icon'] . '"></i> ' . $state['label'], $state['url'], ['class' => 'btn ' . $state['class'], 'style' => 'margin-left: 2em;']); } ?> <?php } else { ?> <?php if (!isset($buttons)) { $icon = Html::tag('i', '', ['class' => 'fa fa-' . $stateChange['state']->icon]); $buttons = [Html::submitButton($icon . $stateChange['state']->label, ['class' => 'btn ' . $stateChange['state']->css_class]), Html::a(Yii::t('app', 'Back'), Url::toRoute([Yii::$app->request->getQueryParam('return', $controller->action->viewAction), 'id' => \netis\crud\crud\Action::exportKey($model->getPrimaryKey(true))]), ['class' => 'btn btn-default'])]; } echo Html::hiddenInput('target-state', $targetState, ['id' => 'target-state']); echo $this->render('_form', ['model' => $model, 'targetState' => $targetState, 'fields' => $fields, 'relations' => $relations, 'formOptions' => array_merge(['action' => Url::toRoute([$controller->action->id, 'id' => $id, 'targetState' => $targetState, 'confirmed' => 1]), 'enableAjaxValidation' => false], isset($formOptions) ? $formOptions : []), 'buttons' => $buttons], $this->context); ?> <?php }