表单字段的使用
<h1>表单字段的使用</h1>
<p>在<code>model-form</code>中内置了大量的form组件来帮助你快速的构建form表单</p>
<p><a name="public"></a></p>
<h2>公共方法</h2>
<p><a name="value"></a></p>
<h3>设置表单值 (value)</h3>
<pre><code class="language-php">$form-&gt;text('title')-&gt;value('text...');</code></pre>
<p><a name="default"></a></p>
<h3>设置默认值 (default)</h3>
<pre><code class="language-php">$form-&gt;text('title')-&gt;default('text...');</code></pre>
<p>此方法仅在<strong>新增页面</strong>有效,如果<strong>编辑页面</strong>也需要设置默认值,可以参考以下方法</p>
<pre><code class="language-php">$form-&gt;text('xxx')-&gt;default('默认值', true);</code></pre>
<p><a name="help"></a></p>
<h3>设置提示信息 (help)</h3>
<pre><code class="language-php">$form-&gt;text('title')-&gt;help('help...');</code></pre>
<p><a name="attr"></a></p>
<h3>设置属性 (attribute)</h3>
<pre><code class="language-php">$form-&gt;text('title')-&gt;attribute(['data-title' =&gt; 'title...']);
$form-&gt;text('title')-&gt;attribute('data-title', 'title...');</code></pre>
<p><a name="required"></a></p>
<h3>设置为必填 (required)</h3>
<pre><code class="language-php">$form-&gt;text('title')-&gt;required();
// 不显示&quot;*&quot;号
$form-&gt;text('title')-&gt;required(false);</code></pre>
<p><a name="disable"></a></p>
<h3>设置为不可编辑 (disable)</h3>
<pre><code class="language-php">$form-&gt;text('title')-&gt;disable();</code></pre>
<p><a name="placeholder"></a></p>
<h3>设置占位符 (placeholder)</h3>
<pre><code class="language-php">$form-&gt;text('title')-&gt;placeholder('请输入。。。');</code></pre>
<p><a name="setWidth"></a></p>
<h3>设置宽度 (width)</h3>
<pre><code class="language-php">$form-&gt;text('title')-&gt;width(8, 2);</code></pre>
<p><a name="rules"></a></p>
<h3>设置验证规则 (rules)</h3>
<p>具体使用可参考<a href="model-form-validation.md">表单验证</a>。</p>
<p><a name="saving"></a></p>
<h3>修改待保存的表单输入值 (saving)</h3>
<p>通过<code>saving</code>方法可以更改待保存数据的格式。</p>
<pre><code class="language-php">use Dcat\Admin\Support\Helper;
$form-&gt;multipleFile('files')-&gt;saving(function ($paths) {
$paths = Helper::array($paths);
// 获取数据库当前行的其他字段
$username = $this-&gt;username;
// 最终转化为json保存到数据库
return json_encode($paths);
});</code></pre>
<p><a name="customFormat"></a></p>
<h3>修改表单数据显示 (customFormat)</h3>
<p>通过<code>customFormat</code>方法可以改变从外部注入到表单的字段值。</p>
<p>如下例子中,<code>multipleFile</code>字段要求待渲染的字段值为数组格式,我们可以通过<code>customFormat</code>方法把从数据库查出的字段值转化为<code>array</code>格式</p>
<pre><code class="language-php">use Dcat\Admin\Support\Helper;
$form-&gt;multipleFile('files')-&gt;saving(function ($paths) {
$paths = Helper::array($paths);
return json_encode($paths);
})-&gt;customFormat(function ($paths) {
// 获取数据库当前行的其他字段
$username = $this-&gt;username;
// 转为数组
return Helper::array($paths);
});</code></pre>
<h3>在弹窗中隐藏</h3>
<p>如果不想在弹窗中显示某个字段,可以使用<code>Form\Field::hideInDialog</code>方法</p>
<pre><code class="language-php">$form-&gt;display('id');
$form-&gt;text('title');
$form-&gt;textarea('contents')-&gt;hideInDialog();</code></pre>
<h3>保存为字符串类型 <code>saveAsString</code></h3>
<p><code>saveAsString</code>方法可以把表单值转化为<code>string</code>类型保存,当保存的数据库字段值不允许为<code>null</code>时非常有用;</p>
<pre><code class="language-php">$form-&gt;text('nickname')-&gt;saveAsString();</code></pre>
<h3>保存为json类型 <code>saveAsJson</code></h3>
<p><code>saveAsJson</code>可以把表单值保存为<code>json</code>格式</p>
<pre><code class="language-php">$form-&gt;text('nickname')-&gt;saveAsJson();</code></pre>
<p><a name="text"></a></p>
<h2>文本 (text)</h2>
<pre><code class="language-php">$form-&gt;text($column, [$label]);
// 添加提交验证规则
$form-&gt;text($column, [$label])-&gt;rules('required|min:10');</code></pre>
<p><a name="hidden"></a></p>
<h2>隐藏字段 (hidden)</h2>
<p>通过<code>hidden</code>方法可以给你的表单设置一个隐藏字段。</p>
<pre><code class="language-php">$form-&gt;hidden('author_id')-&gt;value(Admin::user()-&gt;getKey());</code></pre>
<p>通常可以结合<code>saving</code>事件使用</p>
<pre><code class="language-php">$form-&gt;hidden('author_id');
$form-&gt;saving(function (Form $form) {
$form-&gt;author_id = Admin::user()-&gt;getKey();
});</code></pre>
<p><a name="select"></a></p>
<h2>下拉选框单选 (select)</h2>
<pre><code class="language-php">$form-&gt;select($column[, $label])-&gt;options([1 =&gt; 'foo', 2 =&gt; 'bar', 'val' =&gt; 'Option name']);</code></pre>
<p>或者从api中获取选项列表:</p>
<pre><code class="language-php">$form-&gt;select($column[, $label])-&gt;options('/api/users');
// 使用ajax并显示所选项目
$form-&gt;select($column[, $label])-&gt;options(Model::class)-&gt;ajax('/api/users');
// 或指定名称和ID
$form-&gt;select($column[, $label])-&gt;options(Model::class, 'name', 'id')-&gt;ajax('/api/users');</code></pre>
<p>其中api接口的格式必须为下面格式:</p>
<pre><code class="language-php">[
{
&quot;id&quot;: 9,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 21,
&quot;text&quot;: &quot;xxx&quot;
},
...
]</code></pre>
<p>如果选项过多,可通过ajax方式动态分页载入选项:</p>
<pre><code class="language-php">$form-&gt;select('user_id')-&gt;options(function ($id) {
$user = User::find($id);
if ($user) {
return [$user-&gt;id =&gt; $user-&gt;name];
}
})-&gt;ajax('api/users');</code></pre>
<p>使用model方法在編輯時載入資料:</p>
<pre><code class="language-php">$form-&gt;select('user_id')-&gt;model(User::class, 'id', 'name');</code></pre>
<p>上面的代碼跟下面這個是一樣的</p>
<pre><code class="language-php">$form-&gt;select('user_id')-&gt;options(function ($id) {
$user = User::find($id);
if ($user) {
return [$user-&gt;id =&gt; $user-&gt;name];
}
});</code></pre>
<p>API <code>/admin/api/users</code>接口的代码:</p>
<pre><code class="language-php">public function users(Request $request)
{
$q = $request-&gt;get('q');
return User::where('name', 'like', &quot;%$q%&quot;)-&gt;paginate(null, ['id', 'name as text']);
}
</code></pre>
<p>接口返回的数据结构为</p>
<pre><code class="language-json">{
&quot;total&quot;: 4,
&quot;per_page&quot;: 15,
&quot;current_page&quot;: 1,
&quot;last_page&quot;: 1,
&quot;next_page_url&quot;: null,
&quot;prev_page_url&quot;: null,
&quot;from&quot;: 1,
&quot;to&quot;: 3,
&quot;data&quot;: [
{
&quot;id&quot;: 9,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 21,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 42,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 48,
&quot;text&quot;: &quot;xxx&quot;
}
]
}</code></pre>
<p><a name="selectload"></a></p>
<h2>下拉选框联动 (load)</h2>
<p><code>select</code>组件支持父子关系的单向联动:</p>
<pre><code class="language-php">$form-&gt;select('province')-&gt;options(...)-&gt;load('city', '/api/city');
$form-&gt;select('city');</code></pre>
<p>其中<code>load('city', '/api/city');</code>的意思是,在当前select的选项切换之后,会把当前选项的值通过参数<code>q</code>, 调用接口<code>/api/city</code>,并把api返回的数据填充为city选择框的选项,其中api<code>/api/city</code>返回的数据格式必须符合:</p>
<pre><code class="language-php">[
{
&quot;id&quot;: 9,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 21,
&quot;text&quot;: &quot;xxx&quot;
},
...
]</code></pre>
<p>控制器action的代码示例如下:</p>
<pre><code class="language-php">public function city(Request $request)
{
$provinceId = $request-&gt;get('q');
return ChinaArea::city()-&gt;where('parent_id', $provinceId)-&gt;get(['id', DB::raw('name as text')]);
}</code></pre>
<p><code>selectTable</code>、<code>multipleSelectTable</code>、<code>radio</code>、<code>checkbox</code>也可以使用<code>load</code>方法联动<code>select</code>和<code>multipleSelect</code>表单,用法和上面的示例一致。</p>
<h3>联动多个字段 (loads)</h3>
<p>使用<code>loads</code>方法可以联动多个字段,用法如下</p>
<pre><code class="language-php">$form-&gt;select('status')
-&gt;options(...)
-&gt;loads(['field1', 'field2'], ['/api/field1', '/api/field2']);
$form-&gt;select('field1');
$form-&gt;select('field2');</code></pre>
<p><code>api</code>返回的数据格式与<code>load</code>方法一致,<code>selectTable</code>、<code>multipleSelectTable</code>、<code>radio</code>、<code>checkbox</code>也可以使用<code>loads</code>方法联动。</p>
<p><a name="multipleSelect"></a></p>
<h2>下拉选框多选 (multipleSelect)</h2>
<p>> {tip} 注入这个字段的数据(从数据库查出来的)可以是一个以<code>,</code>隔开的字符串,也可以是<code>json</code>字符串或<code>array</code>数组。</p>
<pre><code class="language-php">$form-&gt;multipleSelect($column[, $label])
-&gt;options([1 =&gt; 'foo', 2 =&gt; 'bar', 'val' =&gt; 'Option name'])
-&gt;saving(function ($value) {
// 转化成json字符串保存到数据库
return json_encode($value);
});
// 使用ajax并显示所选项目:
$form-&gt;multipleSelect($column[, $label])-&gt;options(Model::class)-&gt;ajax('ajax_url');
// 或指定名称和ID
$form-&gt;multipleSelect($column[, $label])-&gt;options(Model::class, 'name', 'id')-&gt;ajax('ajax_url');</code></pre>
<p>多选框可以处理两种情况,第一种是<code>ManyToMany</code>的关系。</p>
<pre><code class="language-php">class Post extends Models
{
public function tags()
{
return $this-&gt;belongsToMany(Tag::class);
}
}
return Form::make(Post::with('tags'), function (Form $form) {
...
$form-&gt;multipleSelect('tags')
-&gt;options(Tag::all()-&gt;pluck('name', 'id'))
-&gt;customFormat(function ($v) {
if (! $v) {
return [];
}
// 从数据库中查出的二维数组中转化成ID
return array_column($v, 'id');
});
});
</code></pre>
<p>第二种是将选项数组存储到单字段中,如果字段是字符串类型,那就需要在模型里面为该字段定义<a href="https://laravel.com/docs/5.5/eloquent-mutators">访问器和修改器</a>来存储和读取了。</p>
<p>如果选项过多,可通过ajax方式动态分页载入选项:</p>
<pre><code class="language-php">$form-&gt;select('friends')-&gt;options(function ($ids) {
return User::find($ids)-&gt;pluck('name', 'id');
})-&gt;ajax('api/users');</code></pre>
<p>API <code>/admin/api/users</code>接口的代码:</p>
<pre><code class="language-php">public function users(Request $request)
{
$q = $request-&gt;get('q');
return User::where('name', 'like', &quot;%$q%&quot;)-&gt;paginate(null, ['id', 'name as text']);
}
</code></pre>
<p>接口返回的数据结构为</p>
<pre><code>{
&quot;total&quot;: 4,
&quot;per_page&quot;: 15,
&quot;current_page&quot;: 1,
&quot;last_page&quot;: 1,
&quot;next_page_url&quot;: null,
&quot;prev_page_url&quot;: null,
&quot;from&quot;: 1,
&quot;to&quot;: 3,
&quot;data&quot;: [
{
&quot;id&quot;: 9,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 21,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 42,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 48,
&quot;text&quot;: &quot;xxx&quot;
}
]
}</code></pre>
<p><a name="select-table"></a></p>
<h2>表格选择器 (selectTable)</h2>
<pre><code class="language-php">use App\Admin\Renderable\UserTable;
use Dcat\Admin\Models\Administrator;
$form-&gt;selectTable($field)
-&gt;title('弹窗标题')
-&gt;dialogWidth('50%') // 弹窗宽度,默认 800px
-&gt;from(UserTable::make(['id' =&gt; $form-&gt;getKey()])) // 设置渲染类实例,并传递自定义参数
-&gt;model(Administrator::class, 'id', 'name'); // 设置编辑数据显示
// 上面的代码等同于
$form-&gt;selectTable($field)
-&gt;from(UserTable::make(['id' =&gt; $form-&gt;getKey()])) // 设置渲染类实例,并传递自定义参数
-&gt;options(function ($v) { // 设置编辑数据显示
if (! $v) {
return [];
}
return Administrator::find($v)-&gt;pluck('name', 'id');
});</code></pre>
<p>定义渲染类如下,需要继承<code>Dcat\Admin\Grid\LazyRenderable</code></p>
<p>> {tip} 这里使用了数据表格异步加载功能,详细用法请参考<a href="lazy.md">异步加载</a></p>
<pre><code class="language-php">&lt;?php
namespace App\Admin\Renderable;
use Dcat\Admin\Grid;
use Dcat\Admin\Grid\LazyRenderable;
use Dcat\Admin\Models\Administrator;
class UserTable extends LazyRenderable
{
public function grid(): Grid
{
// 获取外部传递的参数
$id = $this-&gt;id;
return Grid::make(Administrator::where('xxx_id', $id), function (Grid $grid) {
$grid-&gt;column('id');
$grid-&gt;column('username');
$grid-&gt;column('name');
$grid-&gt;column('created_at');
$grid-&gt;column('updated_at');
$grid-&gt;quickSearch(['id', 'username', 'name']);
$grid-&gt;paginate(10);
$grid-&gt;disableActions();
$grid-&gt;filter(function (Grid\Filter $filter) {
$filter-&gt;like('username')-&gt;width(4);
$filter-&gt;like('name')-&gt;width(4);
});
});
}
}</code></pre>
<p>效果</p>
<p><a href="<a href="https://cdn.learnku.com/uploads/images/202008/23/38389/P5hZXiqAj9.gif!large"">https://cdn.learnku.com/uploads/images/202008/23/38389/P5hZXiqAj9.gif!large"</a>; target="_blank">
<img src="https://cdn.learnku.com/uploads/images/202008/23/38389/P5hZXiqAj9.gif!large" alt="" />
</a></p>
<h3>设置选中后将保存到表单的字段和显示的字段</h3>
<pre><code class="language-php">$form-&gt;selectTable($field)
-&gt;from(UserTable::make(['id' =&gt; $form-&gt;getKey()]))
-&gt;options(function ($v) { // 设置编辑数据显示
if (! $v) {
return [];
}
return Administrator::find($v)-&gt;pluck('name', 'id');
})
-&gt;pluck('name', 'id'); // 第一个参数为显示的字段,第二个参数为选中后将保存到表单的字段
// 上面的代码也可以简化为
$form-&gt;selectTable($field)
-&gt;from(UserTable::make(['id' =&gt; $form-&gt;getKey()]))
-&gt;model(Administrator::class, 'id', 'name'); // 设置编辑数据显示</code></pre>
<h3>多选 (multipleSelectTable)</h3>
<p>多选的用法与上述<code>selectTable</code>方法一致</p>
<pre><code class="language-php">$form-&gt;multipleSelectTable($field)
-&gt;max(10) // 最多选择 10 个选项,不传则不限制
-&gt;from(UserTable::make(['id' =&gt; $form-&gt;getKey()])) // 设置渲染类实例,并传递自定义参数
-&gt;model(Administrator::class, 'id', 'name') // 设置编辑数据显示
-&gt;saving(function ($v) {
// $v 是表单提交的字段值,默认是数组类型,这里需要手动转换一下
// 保存为以 &quot;,&quot; 隔开的字符串,如果是多对多关联关系,则不需要转换。
return implode(',', $v);
});</code></pre>
<h2>多选盒 (listbox)</h2>
<p>使用方法和<code>multipleSelect</code>类似。</p>
<p>> {tip} 注入这个字段的数据(从数据库查出来的)可以是一个以<code>,</code>隔开的字符串,也可以是<code>json</code>字符串或<code>array</code>数组。</p>
<pre><code class="language-php">$form-&gt;listbox($column[, $label])-&gt;options([1 =&gt; 'foo', 2 =&gt; 'bar', 'val' =&gt; 'Option name']);</code></pre>
<p><a name="textarea"></a></p>
<h2>长文本 (textarea)</h2>
<pre><code class="language-php">$form-&gt;textarea($column[, $label])-&gt;rows(10);</code></pre>
<p><a name="radio"></a></p>
<h2>单选 (radio)</h2>
<pre><code class="language-php">$form-&gt;radio($column[, $label])-&gt;options(['m' =&gt; 'Female', 'f'=&gt; 'Male'])-&gt;default('m');</code></pre>
<p><a name="checkbox"></a></p>
<h2>多选 (checkbox)</h2>
<p><code>options()</code>方法用来设置选择项:</p>
<pre><code class="language-php">$form-&gt;checkbox($column[, $label])
-&gt;options([1 =&gt; 'foo', 2 =&gt; 'bar', 'val' =&gt; 'Option name'])
-&gt;saving(function ($value) {
// 转化成json字符串保存到数据库
return json_encode($value);
});</code></pre>
<p>启用选中全部功能</p>
<pre><code class="language-php">$form-&gt;checkbox('column')-&gt;canCheckAll();</code></pre>
<p><a name="autocomplete"></a></p>
<h2>autocomplete</h2>
<p>此表单可以在填写表单时进行对表单值进行搜索,并把结果展示在下拉列表中,用法如下</p>
<pre><code class="language-php">$form-&gt;autocomplete($column[, $label])-&gt;options(['foo', 'bar', ...]);
// 设置分组名称
$form-&gt;autocomplete($column[, $label])-&gt;groups([
[
'label' =&gt; 'group name',
'options' =&gt; ['foo', 'bar', ...],
],
]);</code></pre>
<p>效果如下
<img src="https://cdn.learnku.com/uploads/images/202112/12/38389/ArVNSvChag.png!large" alt="" /></p>
<h3>从远程API获取数据</h3>
<p>也可以从远程API中获取数据</p>
<pre><code class="language-php">// ajax 函数的第一个参数为 ajax url, 第二个参数为 valueField(可选), 第三个参数为 groupField(可选)
$form-&gt;autocomplete($column[, $label])-&gt;ajax('/countries', 'name', 'region');</code></pre>
<p>远程API 服务端的请求参数为query,示例代码如下:</p>
<pre><code class="language-php">class CountryController extends AdminController
{
public function search()
{
$countries = Country::when(request('query'), function ($query, $value) {
$query-&gt;where('name', 'like', &quot;%{$value}%&quot;);
})-&gt;get();
return Admin::json($countries-&gt;toArray());
}
}</code></pre>
<h3>自定义 autocomplete 的设置:</h3>
<p>详细设置请参考: <a href="https://github.com/devbridge/jQuery-Autocomplete">devbridge/jQuery-Autocomplete</a></p>
<pre><code>$js = &lt;&lt;&lt;JS
function (suggestion) {
alert('You selected: ' + suggestion.value + ', ' + suggestion.data);
}
JS;
$form-&gt;autocomplete($column[, $label])-&gt;configs([
'minChars' =&gt; 5,
'noCache' =&gt; true,
'onSelect' =&gt; JavaScript::make($js),
]);</code></pre>
<p>configs 同样也支持闭包:</p>
<pre><code>$form-&gt;autocomplete($column[, $label])-&gt;configs(function($model, $value){
return [
....
];
});</code></pre>
<h3>表单联动</h3>
<p>autocomplete 的联动逻辑和select的刚好相反。
depends 需要写在受影响的字段,不限上级字段类型,上级字段的值将同时上传到API。</p>
<pre><code>$form-&gt;select('region')-&gt;options([
'asia',
'Africa',
'America',
'Europe',
]);
$form-&gt;autocomplete('country')-&gt;ajax('/countries', 'name', 'region');
// 将会发出 /states?query={query}&amp;region={region}&amp;country={country} 的请求
$form-&gt;autocomplete('addr')-&gt;ajax('/states', 'name')-&gt;depends(['region', 'country']);</code></pre>
<p><a name="email"></a></p>
<h2>邮箱 (email)</h2>
<pre><code class="language-php">$form-&gt;email($column[, $label]);</code></pre>
<p><a name="password"></a></p>
<h2>密码 (password)</h2>
<pre><code class="language-php">$form-&gt;password($column[, $label]);</code></pre>
<p><a name="url"></a></p>
<h2>链接 (url)</h2>
<pre><code class="language-php">$form-&gt;url($column[, $label]);</code></pre>
<p><a name="ip"></a></p>
<h2>IP地址 (ip)</h2>
<pre><code class="language-php">$form-&gt;ip($column[, $label]);</code></pre>
<p><a name="mobile"></a></p>
<h2>手机 (mobile)</h2>
<pre><code class="language-php">$form-&gt;mobile($column[, $label])-&gt;options(['mask' =&gt; '999 9999 9999']);</code></pre>
<p><a name="color"></a></p>
<h2>颜色选择器 (color)</h2>
<pre><code class="language-php">$form-&gt;color($column[, $label]);</code></pre>
<p><a name="time"></a></p>
<h2>时间 (time)</h2>
<pre><code class="language-php">$form-&gt;time($column[, $label]);
// 设置时间格式,更多格式参考http://momentjs.com/docs/#/displaying/format/
$form-&gt;time($column[, $label])-&gt;format('HH:mm:ss');</code></pre>
<p><a name="date"></a></p>
<h2>日期 (date)</h2>
<pre><code class="language-php">$form-&gt;date($column[, $label]);
// 设置日期格式,更多格式参考http://momentjs.com/docs/#/displaying/format/
$form-&gt;date($column[, $label])-&gt;format('YYYY-MM-DD');</code></pre>
<p><a name="datetime"></a></p>
<h2>时间日期 (datetime)</h2>
<pre><code class="language-php">$form-&gt;datetime($column[, $label]);
// 设置日期格式,更多格式参考http://momentjs.com/docs/#/displaying/format/
$form-&gt;datetime($column[, $label])-&gt;format('YYYY-MM-DD HH:mm:ss');</code></pre>
<p><a name="timeRange"></a></p>
<h2>时间范围 (timeRange)</h2>
<p><code>$startTime</code>、<code>$endTime</code>为开始和结束时间字段:</p>
<pre><code class="language-php">$form-&gt;timeRange($startTime, $endTime, 'Time Range');</code></pre>
<p><a name="dateRange"></a></p>
<h2>日期范围 (dateRange)</h2>
<p><code>$startDate</code>、<code>$endDate</code>为开始和结束日期字段:</p>
<pre><code class="language-php">$form-&gt;dateRange($startDate, $endDate, 'Date Range');</code></pre>
<p><a name="datetimeRange"></a></p>
<h2>时间日期范围 (datetimeRange)</h2>
<p><code>$startDateTime</code>、<code>$endDateTime</code>为开始和结束时间日期:</p>
<pre><code class="language-php">$form-&gt;datetimeRange($startDateTime, $endDateTime, 'DateTime Range');</code></pre>
<h2>范围 (range)</h2>
<pre><code class="language-php">$form-&gt;range('start_column', 'end_column', '范围');</code></pre>
<p><a name="file"></a></p>
<h2>文件上传 (file)</h2>
<p>使用文件上传功能之前需要先完成上传配置。文件上传配置以及内置方法请参考:<a href="model-form-upload.md">图片/文件上传</a>.</p>
<p>文件上传目录在文件<code>config/admin.php</code>中的<code>upload.file</code>中配置,如果目录不存在,需要创建该目录并开放写权限。</p>
<p>> {tip} 文件或图片上传表单字段请不要在模型中设置<strong>访问器</strong>和<strong>修改器</strong>拼接域名,如有相关需求可参考<a href="model-form-upload.md#withhost">文件/图片域名拼接</a>。</p>
<pre><code class="language-php">$form-&gt;file($column[, $label]);
// 修改文件上传路径和文件名
$form-&gt;file($column[, $label])-&gt;move($dir, $name);
// 并设置上传文件类型
$form-&gt;file($column[, $label])-&gt;rules('mimes:doc,docx,xlsx');
// 添加文件删除按钮
$form-&gt;file($column[, $label])-&gt;removable();</code></pre>
<p><a name="image"></a></p>
<h2>图片上传 (image)</h2>
<p>使用图片上传功能之前需要先完成上传配置。图片上传配置以及内置方法请参考:<a href="model-form-upload.md">图片/文件上传</a>.</p>
<p>图片上传目录在文件<code>config/admin.php</code>中的<code>upload.image</code>中配置,如果目录不存在,需要创建该目录并开放写权限。</p>
<p>可以使用压缩、裁切、添加水印等各种方法,需要先安装<a href="http://image.intervention.io/getting_started/installation">intervention/image</a>。</p>
<p>更多使用方法请参考[<a href="http://image.intervention.io/getting_started/introduction">Intervention</a>]:</p>
<p>> {tip} 文件或图片上传表单字段请不要在模型中设置<strong>访问器</strong>和<strong>修改器</strong>拼接域名,如有相关需求可参考<a href="model-form-upload.md#withhost">文件/图片域名拼接</a>。</p>
<pre><code class="language-php">$form-&gt;image($column[, $label]);
// 修改图片上传路径和文件名
$form-&gt;image($column[, $label])-&gt;move($dir, $name);
// 剪裁图片
$form-&gt;image($column[, $label])-&gt;crop(int $width, int $height, [int $x, int $y]);
// 加水印
$form-&gt;image($column[, $label])-&gt;insert($watermark, 'center');</code></pre>
<p><a name="multipleImage"></a></p>
<h2>多图和多文件上传 (multipleImage/multipleFile)</h2>
<p>多图片上传表单继承自单图上传表单,多文件上传表单继承自单文件上传表单。</p>
<p>> {tip} 注入这个字段的数据(从数据库查出来的)可以是一个以<code>,</code>隔开的字符串,也可以是<code>json</code>字符串或<code>array</code>数组。</p>
<pre><code class="language-php">// 多图
$form-&gt;multipleImage($column[, $label]);
// 限制最大上传数量
$form-&gt;multipleImage($column[, $label])-&gt;limit(3);
// 多文件
$form-&gt;multipleFile($column[, $label]);
// 限制最大上传数量
$form-&gt;multipleFile($column[, $label])-&gt;limit(5);</code></pre>
<p>多图/文件上传的时候提交的数据是一个<code>array</code>数组,你可以通过以下方式把数据在保存进数据库之前改为你想要的格式:</p>
<pre><code class="language-php">// 转化为json格式保存到数据库
$form-&gt;multipleFile($column[, $label])-&gt;saving(function ($paths) {
// 可以转化为由 , 隔开的字符串格式
// return implode(',', $paths);
// 也可以转化为json
return json_encode($paths);
});</code></pre>
<p>当然,如果你想保存为其他任意格式都是可以的,只是如果要保存其他格式,需要通过用<code>customFormat</code>方法把数据转化为一维数组展示,如:</p>
<pre><code class="language-php">$form-&gt;multipleFile($column[, $label])
-&gt;customFormat(function ($paths) {
return collect($paths)-&gt;map(function ($value) {
return explode('|', $value);
})-&gt;flatten()-&gt;toArray();
})
-&gt;saving(function ($paths) {
return implode('|', $paths);
});</code></pre>
<p>启用可排序功能</p>
<pre><code class="language-php">$form-&gt;multipleImage('images')-&gt;sortable();</code></pre>
<p><a name="editor"></a></p>
<h2>富文本编辑器 (editor)</h2>
<p>系统集成了<code>TinyMCE</code>编辑器作为内置编辑器。</p>
<h4>基本使用</h4>
<pre><code class="language-php">$form-&gt;editor($column[, $label]);</code></pre>
<h4>设置语言包</h4>
<p>默认支持简体中文和英文两种语言,如需其他语言可以通过以下方式设置语言包地址。</p>
<pre><code class="language-php">$form-&gt;editor('content')-&gt;languageUrl(url('TinyMCE/langs/de.js'));</code></pre>
<h4>编辑器配置</h4>
<p>具体配置等的使用可以参考<a href="https://www.tiny.cloud/docs">官方文档</a>或<a href="http://tinymce.ax-z.cn/">中文文档</a></p>
<pre><code class="language-php">&lt;?php
use Dcat\Admin\Support\JavaScript;
$form-&gt;editor('content')-&gt;options([
'toolbar' =&gt; [],
'setup' =&gt; JavaScript::make(
&lt;&lt;&lt;JS
function (editor) {
console.log('编辑器初始化成功', editor)
}
JS
),
]);</code></pre>
<h4>设置高度</h4>
<p>默认值为<code>400</code></p>
<pre><code class="language-php">$form-&gt;editor('content')-&gt;height('600');</code></pre>
<h4>只读</h4>
<pre><code class="language-php">$form-&gt;editor('content')-&gt;readOnly();
// 或
$form-&gt;editor('content')-&gt;disable();</code></pre>
<h4>图片上传</h4>
<p>设置图片上传<code>disk</code>配置,默认上传到<code>admin.upload.disk</code>指定的配置</p>
<pre><code class="language-php">// 上传到oss
$form-&gt;editor('content')-&gt;disk('oss');</code></pre>
<p>设置图片上传目录,默认为<code>tinymce/images</code></p>
<pre><code class="language-php">$form-&gt;editor('content')-&gt;imageDirectory('editor/images');</code></pre>
<p>自定义上传接口,接口返回格式需要是<code>{&quot;location&quot;: &quot;图片url&quot;}</code></p>
<pre><code class="language-php">$form-&gt;editor('content')-&gt;imageUrl('editor/upload-image');</code></pre>
<h4>全局设置</h4>
<p>如果你需要对编辑器进行全局设置,可以在<code>app\Admin\bootstrap.php</code>加上以下代码</p>
<pre><code class="language-php">&lt;?php
use Dcat\Admin\Form\Field\Editor;
Editor::resolving(function (Editor $editor) {
// 设置默认配置
$editor-&gt;options([...]);
// 设置编辑器图片默认上传到七牛云
$editor-&gt;disk('qiniu');
});</code></pre>
<p><a name="markdown"></a></p>
<h2>Markdown编辑器 (markdown)</h2>
<p>系统集成了<code>editor-md</code>编辑器作为内置Markdown编辑器。</p>
<h4>基本使用</h4>
<pre><code class="language-php">$form-&gt;markdown($column[, $label]);</code></pre>
<h4>设置语言包</h4>
<p>默认支持简体中文和英文两种语言,如需其他语言可以通过以下方式设置语言包地址。</p>
<pre><code class="language-php">$form-&gt;markdown('content')-&gt;languageUrl(admin_asset('@admin/dcat/plugins/editor-md/languages/zh-tw.js'));</code></pre>
<h4>编辑器配置</h4>
<p>具体配置等的使用可以参考<a href="https://pandao.github.io/editor.md/">官方文档</a></p>
<pre><code class="language-php">&lt;?php
use Dcat\Admin\Support\JavaScript;
$form-&gt;markdown('content')-&gt;options([
'onpreviewing' =&gt; JavaScript::make(
&lt;&lt;&lt;JS
function() {
// console.log(&quot;onpreviewing =&gt;&quot;, this, this.id, this.settings);
// on previewing you can custom css .editormd-preview-active
}
JS
),
]);</code></pre>
<h4>设置高度</h4>
<p>默认值为<code>500</code></p>
<pre><code class="language-php">$form-&gt;markdown('content')-&gt;height('600');</code></pre>
<h4>只读</h4>
<pre><code class="language-php">$form-&gt;markdown('content')-&gt;readOnly();
// 或
$form-&gt;markdown('content')-&gt;disable();</code></pre>
<h4>图片上传</h4>
<p>设置图片上传<code>disk</code>配置,默认上传到<code>admin.upload.disk</code>指定的配置</p>
<pre><code class="language-php">// 上传到oss
$form-&gt;markdown('content')-&gt;disk('oss');</code></pre>
<p>设置图片上传目录,默认为<code>markdown/images</code></p>
<pre><code class="language-php">$form-&gt;markdown('content')-&gt;imageDirectory('markdown/images');</code></pre>
<p>自定义上传接口,接口返回格式需要是<code>{&quot;success&quot;: 1, &quot;url&quot;: &quot;图片url&quot;}</code></p>
<pre><code class="language-php">$form-&gt;markdown('content')-&gt;imageUrl('markdown/upload-image');</code></pre>
<h4>全局设置</h4>
<p>如果你需要对编辑器进行全局设置,可以在<code>app\Admin\bootstrap.php</code>加上以下代码</p>
<pre><code class="language-php">&lt;?php
use Dcat\Admin\Form\Field\Markdown;
Markdown::resolving(function (Markdown $markdown) {
// 设置默认配置
$markdown-&gt;options([...]);
// 设置编辑器图片默认上传到七牛云
$markdown-&gt;disk('qiniu');
});</code></pre>
<p><a name="switch"></a></p>
<h2>开关 (switch)</h2>
<p>使用</p>
<pre><code class="language-php">$form-&gt;switch($column[, $label]);</code></pre>
<p>开关表单保存到数据库的默认值为<code>1</code>和<code>0</code>,如果需要更改保存到数据库的值,可以这样使用</p>
<pre><code class="language-php">$form-&gt;switch($column[, $label])
-&gt;customFormat(function ($v) {
return $v == '打开' ? 1 : 0;
})
-&gt;saving(function ($v) {
return $v ? '打开' : '关闭';
});</code></pre>
<p><a name="map"></a></p>
<h2>地图 (map)</h2>
<p>地图控件,用来选择经纬度,<code>$latitude</code>, <code>$longitude</code>为经纬度字段。</p>
<p>使用这个功能需要在 <code>config/admin.php</code> 文件中修改 <code>map_provider</code> 的值(目前支持的地图为:"tencent", "google", "yandex",不同地图需要自己申请相应的 KEY 并在 .env 文件中配置,然后需要在<code>app/Admin/bootstrap.php</code>中加入以下代码</p>
<pre><code class="language-php">Form\Field\Map::requireAssets();</code></pre>
<p>使用</p>
<pre><code class="language-php">$form-&gt;map($latitude, $longitude, $label);</code></pre>
<p><a name="slider"></a></p>
<h2>滑动条 (slider)</h2>
<p>可以用来数字类型字段的选择,比如年龄:</p>
<pre><code class="language-php">$form-&gt;slider($column[, $label])-&gt;options(['max' =&gt; 100, 'min' =&gt; 1, 'step' =&gt; 1, 'postfix' =&gt; 'years old']);</code></pre>
<p>更多options请参考:<a href="https://github.com/IonDen/ion.rangeSlider#settings">https://github.com/IonDen/ion.rangeSlider#settings</a></p>
<p><a name="display"></a></p>
<h2>仅显示 (display)</h2>
<p>只显示字段,不做任何操作:</p>
<pre><code class="language-php">$form-&gt;display($column[, $label]);
//更复杂的显示
$form-&gt;display($column[, $label])-&gt;with(function ($value) {
return &quot;&lt;img src=&quot;$value&quot; /&gt;&quot;;
});</code></pre>
<p><a name="currency"></a></p>
<h2>单位符号 (currency)</h2>
<pre><code class="language-php">$form-&gt;currency($column[, $label]);
// 设置单位符号
$form-&gt;currency($column[, $label])-&gt;symbol('¥');</code></pre>
<p><a name="number"></a></p>
<h2>数字 (number)</h2>
<pre><code class="language-php">$form-&gt;number($column[, $label]);</code></pre>
<p><a name="rate"></a></p>
<h2>费率 (rate)</h2>
<pre><code class="language-php">$form-&gt;rate($column[, $label]);</code></pre>
<p><a name="divider"></a></p>
<h2>分割线 (divider)</h2>
<pre><code class="language-php">$form-&gt;divider();</code></pre>
<p><a name="html"></a></p>
<h2>自定义内容 (html)</h2>
<p>插入html内容,参数可以是实现了<code>Htmlable</code>、<code>Renderable</code>或者实现了<code>__toString()</code>方法的类</p>
<pre><code class="language-php">$form-&gt;html('你的html内容', $label = '');</code></pre>
<p><a name="tags"></a></p>
<h2>标签 (tags)</h2>
<p>插入逗号(,)隔开的字符串<code>tags</code></p>
<pre><code class="language-php">$form-&gt;tags('keywords');</code></pre>
<p><code>tags</code>同样支持<code>ManyToMany</code>的关系,示例如下:</p>
<pre><code class="language-php">$form-&gt;tags('tags', '文章标签')
-&gt;pluck('name', 'id') // name 为需要显示的 Tag 模型的字段,id 为主键
-&gt;options(Tag::all());// 下拉框选项</code></pre>
<p>注意:处理<code>ManyToMany</code>关系时必须调用<code>pluck</code>方法,指定显示的字段名和主键。
此外 <code>options</code> 方法传入一个<code>Collection</code>对象时,<code>options</code>会自动调用该对象的<code>pluck</code>方法转为<code>['主键名' =&gt; '显示字段名']</code> 数组,作为下拉框选项。或者可以直接使用<code>['主键名' =&gt; '显示字段名']</code>这样的数组作为参数。</p>
<p><code>tags</code>还支持<code>saving</code>方法用于处理提交的数据,示例如下:</p>
<pre><code class="language-php">$form-&gt;tags('tags', '文章标签')
-&gt;pluck('name', 'id')
-&gt;options(Tag::all())
-&gt;saving(function ($value) {
return $value;
});</code></pre>
<p><code>saving</code> 方法接收一个「参数为 tags 的提交值,返回值为修改后的 tags 提交值」的闭包,可以用于实现自动创建新 tag 或其它功能。</p>
<p>如果选项过多,可通过ajax方式动态分页载入选项:</p>
<pre><code class="language-php">$form-&gt;tags('friends')-&gt;options(function ($ids) {
return User::find((array) $ids)-&gt;pluck('name', 'id');
})-&gt;ajax('api/users');</code></pre>
<p>API <code>/admin/api/users</code>接口的代码:</p>
<pre><code class="language-php">public function users(Request $request)
{
$q = $request-&gt;get('q');
return User::where('name', 'like', &quot;%$q%&quot;)-&gt;paginate(null, ['id', 'name as text']);
}</code></pre>
<p>接口返回的数据结构为</p>
<pre><code>{
&quot;total&quot;: 4,
&quot;per_page&quot;: 15,
&quot;current_page&quot;: 1,
&quot;last_page&quot;: 1,
&quot;next_page_url&quot;: null,
&quot;prev_page_url&quot;: null,
&quot;from&quot;: 1,
&quot;to&quot;: 3,
&quot;data&quot;: [
{
&quot;id&quot;: 9,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 21,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 42,
&quot;text&quot;: &quot;xxx&quot;
},
{
&quot;id&quot;: 48,
&quot;text&quot;: &quot;xxx&quot;
}
]
}</code></pre>
<p><a name="icon"></a></p>
<h2>图标选择器 (icon)</h2>
<p>选择<code>font-awesome</code>图标</p>
<pre><code class="language-php">$form-&gt;icon('icon');</code></pre>
<p><a name="tree"></a></p>
<h2>树形选择器 (tree)</h2>
<p>树形结构表单</p>
<pre><code class="language-php">$form-&gt;tree('permissions')
-&gt;nodes(Model::get()-&gt;toArray()) // 设置所有节点
-&gt;customFormat(function ($v) { // 格式化外部注入的值
if (!$v) return [];
return array_column($v, 'id');
});
// 修改节点的字段名称
// 默认 “id” “name” “parent_id”
$form-&gt;tree('permissions')
-&gt;nodes($permissionModel-&gt;allNodes())
-&gt;setIdColumn('id')
-&gt;setTitleColumn('title')
-&gt;setParentColumn('parent');
// 默认是不保存父节点的值的,因为一般来说父节点只是作为标题的形式存在
// 禁止过滤父节点的值
$form-&gt;tree('permissions')
-&gt;nodes($permissionModel-&gt;allNodes())
-&gt;exceptParentNode(false);
// 默认收缩子节点
$form-&gt;tree('permissions')
-&gt;nodes($permissionModel-&gt;allNodes())
-&gt;expand(false);</code></pre>
<p><code>tree</code>表单默认不允许单独选中父节点,可以通过<code>treeState(false)</code>开启这个功能</p>
<pre><code class="language-php">$form-&gt;tree('xxx')
-&gt;treeState(false) # 允许单独选择父节点
-&gt;setTitleColumn('title')
-&gt;nodes(...);</code></pre>
<p>效果</p>
<p><img src="https://cdn.learnku.com/uploads/images/202104/30/38389/oChwzky2BT.gif!large" alt="" /></p>
<p><a name="table"></a></p>
<h2>表格表单 (table)</h2>
<p>如果某一个字段存储的是json格式的二维数组,可以使用table表单组件来实现快速的编辑:</p>
<pre><code class="language-php">$form-&gt;table('extra', function (NestedForm $table) {
$table-&gt;text('key');
$table-&gt;text('value');
$table-&gt;text('desc');
});</code></pre>
<p>同时在模型里面给这个字段增加访问器和修改器:</p>
<pre><code class="language-php">public function getExtraAttribute($extra)
{
return array_values(json_decode($extra, true) ?: []);
}
public function setExtraAttribute($extra)
{
$this-&gt;attributes['extra'] = json_encode(array_values($extra));
}</code></pre>
<p>这个组件类似于hasMany组件,不过是用来处理单个字段的情况,适用于简单的二维数据。</p>
<p><a name="onemany"></a></p>
<h2>一对多 (hasMany)</h2>
<p>一对多内嵌表格,用于处理一对多的关系,下面是个简单的例子:</p>
<p>有两张表是一对多关系:</p>
<pre><code class="language-sql">CREATE TABLE `demo_painters` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`bio` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `demo_paintings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`painter_id` int(10) unsigned NOT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`body` text COLLATE utf8_unicode_ci NOT NULL,
`completed_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY painter_id (`painter_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;</code></pre>
<p>表的模型为:</p>
<pre><code class="language-php">&lt;?php
namespace App\Models\Demo;
use Illuminate\Database\Eloquent\Model;
class Painter extends Model
{
public function paintings()
{
return $this-&gt;hasMany(Painting::class, 'painter_id');
}
}</code></pre>
<pre><code class="language-php">&lt;?php
namespace App\Models\Demo;
use Illuminate\Database\Eloquent\Model;
class Painting extends Model
{
protected $fillable = ['title', 'body', 'completed_at'];
public function painter()
{
return $this-&gt;belongsTo(Painter::class, 'painter_id');
}
}</code></pre>
<p>构建表单代码如下:</p>
<pre><code class="language-php">use App\Models\Demo\Painter;
// 这里需要显式地指定关联关系
$builder = Painter::with('paintings');
// 如果你使用的是数据仓库,则可以这样指定关联关系
// $repository = new Painter(['paintings']);
return Form::make($builder, function (Form $form) {
$form-&gt;display('id', 'ID');
$form-&gt;text('username')-&gt;rules('required');
$form-&gt;textarea('bio')-&gt;rules('required');
$form-&gt;hasMany('paintings', function (Form\NestedForm $form) {
$form-&gt;text('title');
$form-&gt;textarea('body');
$form-&gt;datetime('completed_at');
});
$form-&gt;display('created_at', 'Created At');
$form-&gt;display('updated_at', 'Updated At');
// 也可以设置label
// $form-&gt;hasMany('paintings', '画作', function (Form\NestedForm $form) {
// ...
// });
});</code></pre>
<p>效果</p>
<p><img src="{{public}}/assets/img/screenshots/has-many.png" alt="" /></p>
<p><a name="has-many-table"></a></p>
<h3>表格模式 (table)</h3>
<p>如果你想要显示表格模式,可以这样使用</p>
<pre><code class="language-php">use Dcat\Admin\Support\Helper;
$form-&gt;hasMany('paintings', function (Form\NestedForm $form) {
...
})-&gt;useTable();</code></pre>
<p>效果</p>
<p><a href="{{public}}/assets/img/screenshots/has-many-table.png" target="_blank">
<img src="{{public}}/assets/img/screenshots/has-many-table.png" style="box-shadow:0 1px 6px 1px rgba(0, 0, 0, 0.12)" width="100%">
</a></p>
<p><a name="embeds"></a></p>
<h2>内嵌 (embeds)</h2>
<p>> {tip} 内嵌表单不支持图片和文件上传表单。</p>
<p>用于处理<code>mysql</code>的<code>JSON</code>类型字段数据或者<code>mongodb</code>的<code>object</code>类型数据,也可以将多个field的数据值以<code>JSON</code>字符串的形式存储在<code>mysql</code>的字符串类型字段中</p>
<p>比如<code>orders</code>表中的<code>JSON</code>或字符串类型的<code>extra</code>字段,用来存储多个field的数据,先定义model:</p>
<pre><code class="language-php">class Order extends Model
{
protected $casts = [
'extra' =&gt; 'json',
];
}</code></pre>
<p>然后在form中使用:</p>
<pre><code class="language-php">$form-&gt;embeds('extra', function ($form) {
$form-&gt;text('extra1')-&gt;rules('required');
$form-&gt;email('extra2')-&gt;rules('required');
$form-&gt;mobile('extra3');
$form-&gt;datetime('extra4');
$form-&gt;dateRange('extra5', 'extra6', '范围')-&gt;rules('required');
});
// 自定义标题
$form-&gt;embeds('extra', '附加信息', function ($form) {
...
});</code></pre>
<p>回调函数里面构建表单元素的方法调用和外面是一样的。</p>