synatree / yii2-dynamic-relations
允许Yii2视图包含基于模型关系的动态扩展字段集。
Requires
- yiisoft/yii2: *
This package is not auto-updated.
Last update: 2024-09-28 16:41:28 UTC
README
这个扩展是在我徒劳地搜索像这样的东西之后出现的:
- 动态从“主”视图创建“子”模型
- 动态添加到Yii2视图的输入
- 在相关模型中使用Yii2小部件
- 动态向表单添加字段
希望上面的内容能节省其他人一些搜索时间。
这能做什么?
允许Yii2视图包含基于模型关系的动态扩展字段集。
此系统允许您定义一个视图,通常称为_inline.php,当用户点击表单上的“添加”按钮时,该视图将被自动加载。
幕后,模块负责处理保存相关记录(如果它们是新的),更新它们(如果它们已被更改),以及删除它们(如果它们被删除)。
这基本上是通过Ajax添加任意扩展的相关记录集到模型的一种方式。
它还被设计成智能地移动视图小部件可能使用的JavaScript和事件绑定,以避免在通过ajax添加多个“相同”视图时相互冲突。坦白地说,管理由此产生的JavaScript冲突是这里最大的时间节省。
我不确定安全影响实际上有多大,但为了安全起见,我还将代码的ajax请求部分与用户的会话绑定,因此用户会话丢失后重放相同的请求不应该可能。设置方式也基本上隐藏了内联视图的真实名称和路径;我只是不喜欢脚本将服务器端文件路径泄漏到HTML代码中。
安装
安装此扩展的最佳方式是通过composer。
运行以下命令之一:
php composer.phar require synatree/yii2-dynamic-relations "dev-master"
或者
"synatree/yii2-dynamic-relations": "dev-master"
将以下内容添加到您的 composer.json
文件的 require 部分。
接下来,您必须将以下内容添加到您的模块配置中:
'modules' => [ ... 'dynamicrelations' => [ 'class' => '\synatree\dynamicrelations\Module' ], ...
用法
您应该做的第一件事是为要动态使用的模型创建一个名为 _inline.php 的视图。此视图可以包含任意小部件,它已与Krajee的一些小部件进行了测试。
这是最复杂的一部分,因为我们必须确保每次调用此视图时,生成的HTML和脚本都是唯一的。
您还必须告诉DynamicRelations如何通过提供路由来添加和删除模型。
最后,您必须保持字段名称的某种结构,以便小部件可以在提交时识别新模型和现有模型。示例
use synatree\dynamicrelations\DynamicRelations; use kartik\widgets\ActiveForm; use kartik\datecontrol\DateControl; use yii\helpers\Url; /* @var $this yii\web\View */ /* @var $model app\models\BusinessHours */ /* @var $form kartik\widgets\ActiveForm */ // generate something globally unique. $uniq = uniqid(); if( $model->primaryKey ) { // you must define an attribute called "data-dynamic-relation-remove-route" if you plan to allow inline deletion of models from the form. $removeAttr = 'data-dynamic-relation-remove-route="' . Url::toRoute(['business-hours/delete', 'id'=>$model->primaryKey]) . '"'; $frag = "BusinessHours[{$model->primaryKey}]"; } else { $removeAttr = ""; // new models must go under a key called "[new]" $frag = "BusinessHours[new][$uniq]"; } ?> <div class="BusinessHours-form form-inline" <?= $removeAttr; ?>> <?= DateControl::widget([ 'type' => DateControl::FORMAT_DATE, 'name' => $frag.'[day]', // expanded, this ends up being something like BusinessHours[1][day] or BusinessHours[new][random][day] 'value' => $model->day, // for Kartik widgets, include the following line. This basically generates a globally unique set of pluginOptions, which is important to prevent // javascript errors and make sure everything works as expected. 'options' => DynamicRelations::uniqueOptions('day',$uniq) ]);?> .... More widgets use the same structure as above .... </div>
下一步是设置控制器以保存您期望接收的相关模型。在以下示例中,我们只需要在每个创建和更新操作方法中添加一行小代码。
use synatree\dynamicrelations\DynamicRelations; use app\models\BusinessHours; use yii\web\Controller; class SomeController extends Controller { /** * Creates a new SomethingModel model. * If creation is successful, the browser will be redirected to the 'view' page. * @return mixed */ public function actionCreate() { $model = new SomethingModel(); if ($model->load(Yii::$app->request->post()) && $model->save()) { // this next line is the only one added to a standard Gii-created controller action: DynamicRelations::relate($model, 'hours', Yii::$app->request->post(), 'BusinessHours', BusinessHours::className()); // Parent Model --^ ^-- Attribute ^-- Array to search ^-- Root Key ^-- Model Class Name return $this->redirect(['view', 'id' => $model->primaryKey]); } else { return $this->render('create', [ 'model' => $model, ]); } } public function actionUpdate($id) { ... if ($model->save()) { // this next line exactly the same as in actionCreate: DynamicRelations::relate($model, 'hours', Yii::$app->request->post(), 'BusinessHours', BusinessHours::className()); return $this->redirect(['view', 'id' => $model->boatShowId]); } else { return $this->render('update', [ 'model' => $model, ]); } ... } }
为了支持Ajax删除相关记录,修改您的相关模型控制器
/** * Deletes an existing BusinessHours model. * If deletion is successful, the browser will be redirected to the 'index' page. * @param integer $id * @return mixed */ public function actionDelete($id) { $this->findModel($id)->delete(); if(! Yii::$app->request->isAjax){ return $this->redirect(['index']); } else { return "OK"; } }
最后,在您对父模型的看法中,对于每个您想要动态添加的相关模型,包括以下类似的行。
use synatree\dynamicrelations\DynamicRelations; <?= DynamicRelations::widget([ 'title' => 'Business Hours', 'collection' => $model->hours, 'viewPath' => '@app/views/business-hours/_inline.php', // this next line is only needed if there is a chance that the collection above will be empty. This gives the script a prototype to work with. 'collectionType' => new \app\models\BusinessHours, ]); ?>
这样应该就完成了。我希望这能帮助到人们,我真的很希望这个功能能实现。