php laravel管理员相关类库

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php laravel管理员相关类库相关的知识,希望对你有一定的参考价值。

# laravel-admin的代码片段


## laravel的switch 
修改form下的开关为中文文案
SwitchField.php

其中动态修改单个值,通过:
```php
    $form->switch('charge_type', '房间属性')->states([
        'on.text' => '计费', // 1
        'off.text' => '免费', // 0
    ]);
```


## 一个按钮,点击复制值
LongUrl.php


## Form
> AsyncRender  


## column
> ExpandRow  




## laravel-admin生成控制器代码
有4个文件:  
> controller.stub  
> controller.show.stub  
> MakeTemplateControllerCommand.php  
> ResourceGenerator.php  


<?php

namespace App\Admin\Extensions\Grid;


use Encore\Admin\Grid\Displayers\AbstractDisplayer;
use Qiniu\Processing\ImageUrlBuilder;

/**
 * laravel-admin里显示小图片
 * 可以用来显示多个小图片
 * 图片基于七牛
 * 需要继承
 *
 * Class ShowSmallImage
 * @package App\Admin\Extensions\Grid
 */
abstract class ShowSmallImageBase extends AbstractDisplayer
{
    protected $width = 80;
    protected $height = 60;
    protected $model = 2;

    /**
     * 图片地址的分割符
     *
     * @var string
     */
    protected $delimiter = ',';

    /**
     * 配置filesystems.disk里的key
     * 需定义
     *
     * @abstract
     * @var string|null
     */
    protected $disk = null;


    /**
     * 显示七牛小图
     *
     * $grid->column('img', '图片')->showSmallImage();
     *
     * @return array|mixed|string
     */
    public function display()
    {
        $args = func_get_args();
        $this->model = $args[0] ?? $this->model;
        $this->width = $args[1] ?? $this->width; // 可改为small类型
        $this->height = $args[2] ?? $this->height;
        $value = $this->value;

        if (empty($value)) {
            return '';
        }

        if (is_string($value)) {
            $value = explode($this->delimiter, $value);
        }

        $html = '';
        foreach ($value as $image) {
            $html .= $this->imgHtml($image);
        }

        return $html;
    }

    protected function imgHtml($image)
    {
        if (empty($image)) {
            return '';
        }

        if (!ifStartHttp($image)) { // 不自带域名
            $image = $this->handleNotStartHttp($image);
        }
        $image = $this->handleQiNiu($image);

        return  "<img src=\"{$image}\" width=\"{$this->width}\" height=\"{$this->height}\" />";
    }

    protected function ifQiNiuPic($image)
    {
        $domain = getStorageConfig('domain', $this->disk);
        $domain = parse_url($domain, PHP_URL_HOST);

        return ifStartHttp($image, $domain);
    }

    protected function handleQiNiu($image)
    {
        if (!$this->ifQiNiuPic($image)) {
            return $image;
        }

        return (new ImageUrlBuilder())->thumbnail($image, $this->model, $this->width, $this->height);
    }

    abstract protected function handleNotStartHttp($image);
}
<?php
/**
 * Created by PhpStorm.
 * User: code
 * Date: 2018/3/5
 * Time: 下午2:54
 */

namespace App\Admin\Extensions\Form;


class SwitchField extends \Encore\Admin\Form\Field\SwitchField
{


    protected $states = [
        'on'  => ['value' => 1, 'text' => '是', 'color' => 'success'],
        'off' => ['value' => 0, 'text' => '否', 'color' => 'danger'],
    ];


}
<?php

namespace App\Admin\Extensions\Grid;

/**
 * 修改默认开关的文案(改为中文)
 *
 * @package App\Admin\Extensions\Form
 */
class SwitchDisplay extends \Encore\Admin\Grid\Displayers\SwitchDisplay
{
    protected $states = [
        'on'  => ['value' => 1, 'text' => '是', 'color' => 'success'],
        'off' => ['value' => 0, 'text' => '否', 'color' => 'danger'],
    ];
    


}
<?php

namespace App\Admin\Extensions\Grid;


use Encore\Admin\Grid\Displayers\AbstractDisplayer;

class SelectText extends AbstractDisplayer
{


    /**
     * 在数组中显示对应值的文案
     *
     * $grid->column('type', '类型')->selectText($typeArr);
     *
     * @return array|mixed|string
     */
    public function display()
    {
        $data = current(func_get_args());

        $value = $this->value;

        if (!isset($value)) {
            return '';
        }

        return $data[$value]??'';
    }

}
<?php
/**
 * Created by PhpStorm.
 * User: code
 * Date: 2018/3/5
 * Time: 下午3:02
 */

namespace App\Admin\Extensions\Grid;

use Encore\Admin\Admin;
use Encore\Admin\Grid\Displayers\AbstractDisplayer;


/**
 * 一个按钮,点击复制值
 *
 * Class longUrl
 * @package App\Admin\Extensions\Grid
 */
class LongUrl extends AbstractDisplayer
{

    const ID_CLIPBOARD_JS = 'id-clipboard-js';


    public function display()
    {
        $name = $this->column->getName();

        $class = "grid-long-url-{$name}";
        $jsId = self::ID_CLIPBOARD_JS;


        $script = <<<EOT
        
    if (window['Clipboard']){
        new Clipboard('.{$class}')
    }else{
        $('#{$jsId}').ready(function (){
            setTimeout(function (){
                if (window['Clipboard']){
                    new Clipboard('.{$class}')
                }else{
                    console.error('还是没有Clipboard');
                }
            }, 0);
        });
    }

EOT;


        // 一定要在\Encore\Admin\Layout\Content中添加row,一个script,否则异步的pjax就会过滤掉js加载
//        \Encore\Admin\Admin::js('https://cdn.staticfile.org/clipboard.js/1.5.16/clipboard.min.js');
        Admin::script($script);

        return <<<EOT
        <button class="{$class}  btn btn-default" data-clipboard-text="{$this->value}" title="{$this->value}">复制</button>
EOT;


    }



}
<?php
/**
 * Created by PhpStorm.
 * User: code
 * Date: 2019/4/3
 * Time: 17:23
 */

namespace App\Admin\Extensions\Form;

/**
 * 解决null值保存,强制转换为string
 */
class Text extends \Encore\Admin\Form\Field\Text
{
    public function prepare($value)
    {
        return (string)parent::prepare($value);
    }
}
<!-- 放在resources/views/vendor/laravel-admin-logs/logs.blade.php中 -->
<script data-exec-on-popstate>

    $(function () {
        LA.intervalIds = [];
        LA.addIntervalId = function (intervalId, persist) {
            this.intervalIds.push({id:intervalId, persist:persist});
        };

        LA.clearIntervalId = function (intervalId) {
            for (var id in this.intervalIds) {
                if (intervalId == this.intervalIds[id].id && !this.intervalIds[id].persist) {
                    clearInterval(intervalId);
                    this.intervalIds.splice(id, 1);
                }
            }
        };

        LA.cleanIntervalId = function () {
            for (var id in this.intervalIds) {
                if (!this.intervalIds[id].persist) {
                    clearInterval(this.intervalIds[id].id);
                    this.intervalIds.splice(id, 1);
                }
            }
        };

        $(document).on('pjax:complete', function(xhr) {
            $.admin.cleanIntervalId();
        });

        $('.log-refresh').on('click', function() {
            $.pjax.reload('#pjax-container');
        });

        var pos = {{ $end }};

        function changePos(offset){
            pos = offset;
        }

        // 此处修改,增加fetch结束的变量
        var fetchWait = 1;
        function fetch() {
            if (fetchWait){
                fetchWait = 0;
            }else{
                return;
            }

            $.ajax({
                url:'{{ $tailPath }}',
                method: 'get',
                data : {offset : pos},
                success:function(data) {
                    fetchWait = 1;
                    for (var i in data.logs) {
                        $('table > tbody > tr:first').before(data.logs[i]);
                    }
                    changePos(data.pos);
                }
            });
        }

        var refreshIntervalId = null;

        $('.log-live').click(function() {
            $("i", this).toggleClass("fa-play fa-pause");

            if (refreshIntervalId) {
                $.admin.clearIntervalId(refreshIntervalId);
                refreshIntervalId = null;
            } else {
                refreshIntervalId = setInterval(function() {
                    fetch();
                }, 2000);
                $.admin.addIntervalId(refreshIntervalId, false);
            }
        });
    });


</script>
<div class="row">

    <!-- /.col -->
    <div class="col-md-10">
        <div class="box box-primary">
            <div class="box-header with-border">
                <button type="button" class="btn btn-primary btn-sm log-refresh"><i class="fa fa-refresh"></i> {{ trans('admin.refresh') }}</button>
                <button type="button" class="btn btn-default btn-sm log-live"><i class="fa fa-play"></i> </button>
                <div class="pull-right">
                    <div class="btn-group">
                        @if ($prevUrl)
                        <a href="{{ $prevUrl }}" class="btn btn-default btn-sm"><i class="fa fa-chevron-left"></i></a>
                        @endif
                        @if ($nextUrl)
                        <a href="{{ $nextUrl }}" class="btn btn-default btn-sm"><i class="fa fa-chevron-right"></i></a>
                        @endif
                    </div>
                    <!-- /.btn-group -->
                </div>
                <!-- /.box-tools -->
            </div>
            <!-- /.box-header -->
            <div class="box-body no-padding">

                <div class="table-responsive">
                    <table class="table table-hover">

                        <thead>
                            <tr>
                                <th>Level</th>
                                <th>Env</th>
                                <th>Time</th>
                                <th>Message</th>
                                <th></th>
                            </tr>
                        </thead>

                        <tbody>

                        @foreach($logs as $index => $log)

                            <tr>
                                <td><span class="label bg-{{\Encore\Admin\LogViewer\LogViewer::$levelColors[$log['level']]}}">{{ $log['level'] }}</span></td>
                                <td><strong>{{ $log['env'] }}</strong></td>
                                <td style="width:150px;">{{ $log['time'] }}</td>
                                <td><code style="word-break: break-all;">{{ $log['info'] }}</code></td>
                                <td>
                                    @if(!empty($log['trace']))
                                    <a class="btn btn-primary btn-xs" data-toggle="collapse" data-target=".trace-{{$index}}"><i class="fa fa-info"></i>&nbsp;&nbsp;Exception</a>
                                    @endif
                                </td>
                            </tr>

                            @if (!empty($log['trace']))
                            <tr class="collapse trace-{{$index}}">
                                <td colspan="5"><div style="white-space: pre-wrap;background: #333;color: #fff; padding: 10px;">{{ $log['trace'] }}</div></td>
                            </tr>
                            @endif

                        @endforeach

                        </tbody>
                    </table>
                    <!-- /.table -->
                </div>
                <!-- /.mail-box-messages -->
            </div>
            <!-- /.box-body -->
        </div>
        <!-- /. box -->
    </div>

    <div class="col-md-2">

        <div class="box box-solid">
            <div class="box-header with-border">
                <h3 class="box-title">Files</h3>
            </div>
            <div class="box-body no-padding">
                <ul class="nav nav-pills nav-stacked">
                    @foreach($logFiles as $logFile)
                        <li @if($logFile == $fileName)class="active"@endif>
                            <a href="{{ route('log-viewer-file', ['file' => $logFile]) }}"><i class="fa fa-{{ ($logFile == $fileName) ? 'folder-open' : 'folder' }}"></i>{{ $logFile }}</a>
                        </li>
                    @endforeach
                </ul>
            </div>
            <!-- /.box-body -->
        </div>

        <div class="box box-solid">
            <div class="box-header with-border">
                <h3 class="box-title">Info</h3>
            </div>
            <div class="box-body no-padding">
                <ul class="nav nav-pills nav-stacked">
                    <li class="margin: 10px;">
                        <a>Size: {{ $size }}</a>
                    </li>
                    <li class="margin: 10px;">
                        <a>Updated at: {{ date('Y-m-d H:i:s', filectime($filePath)) }}</a>
                    </li>
                </ul>
            </div>
            <!-- /.box-body -->
        </div>

        <!-- /.box -->
    </div>
    <!-- /.col -->
</div>
<?php
/**
 * Created by PhpStorm.
 * User: code
 * Date: 2019/4/3
 * Time: 10:48
 */

namespace App\Admin\Controllers;

use Encore\Admin\Layout\Content;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use \App\User as Model;

abstract class AdminTemplateController extends AdminController
{
    /**
     * 页名
     *
     * @var string
     */
    protected $headerText = '';

    /**
     * Index interface.
     *
     * @param Content $content
     * @return Content
     */
    public function index(Content $content)
    {
        return $content
            ->header('列表')
            ->description($this->headerText . '的列表')
            ->body($this->grid());
    }


    /**
     * Edit interface.
     *
     * @param mixed   $id
     * @param Content $content
     * @return Content
     */
    public function edit($id, Content $content)
    {
        return $content
            ->header('编辑')
            ->description($this->headerText . '的编辑')
            ->body($this->form()->edit($id));
    }

    /**
     * Create interface.
     *
     * @param Content $content
     * @return Content
     */
    public function create(Content $content)
    {
        return $content
            ->header('创建')
            ->description($this->headerText . '的创建')
            ->body($this->form());
    }

    /**
     * 覆盖
     * demo
     *
     * @return Grid
     */
    protected function grid()
    {
        $model = new Model;
        $grid = new Grid($model);

        $grid->id('ID')->sortable();

        $grid->created_at('创建时间');
        $grid->updated_at('更新时间');

        return $grid;
    }

    /**
     * 覆盖
     * demo
     *
     * @return Form
     */
    protected function form()
    {
        $model = new Model;
        $form = new Form($model);

        $form->display('id', 'ID');

        $form->display(Model::CREATED_AT, '创建时间');
        $form->display(Model::UPDATED_AT, '更新时间');

        return $form;
    }
}
<?php

namespace DummyNamespace;

use App\Admin\Controllers\AdminTemplateController;
use DummyModelNamespace as Model;
use Encore\Admin\Form;
use Encore\Admin\Grid;

class DummyClass extends AdminTemplateController
{
DummyProtected

    protected function grid()
    {
        $model = new Model;
        $grid = new Grid($model);

DummyGrid

        return $grid;
    }

    protected function form()
    {
        $model = new Model;
        $form = new Form($model);

DummyForm

        return $form;
    }

}
<?php

namespace DummyNamespace;

use App\Admin\Controllers\AdminTemplateController;
use DummyModelNamespace as Model;
use Encore\Admin\Grid;

class DummyClass extends AdminTemplateController
{
DummyProtected

    protected function grid()
    {
        $model = new Model;
        $grid = new Grid($model);

DummyGrid

        return $grid;
    }


}
<?php
/**
 * Created by PhpStorm.
 * User: code
 * Date: 2019/4/22
 * Time: 18:18
 */

namespace App\Helper\Vendor\LaravelAdmin;

/**
 * 添加到:\App\Console\Kernel::$commands
 *
 * @example php artisan admin:make:template_controller UserFriend
 * @example php artisan admin:make:template_controller UserFriend --disSave
 */
class MakeTemplateControllerCommand extends \Encore\Admin\Console\MakeCommand
{
    /**
     * @var \App\Helper\Vendor\LaravelAdmin\ResourceGenerator
     */
    protected $generator;

    /**
     * The console command name.
     *
     * @var string
     */
    protected $signature = 'admin:make:template_controller {name} 
        {--model=} 
        {--stub= : Path to the custom stub file. } 
        {--O|output}
        {--disSave}
        {--disEdit}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '创建Laravel-Admin的后台控制器,根据后台模板控制器';

    /**
     * 入口
     *
     * @return void|bool
     */
    public function handle()
    {
        $this->handleModelNull();

        return parent::handle();
    }

    /**
     * 处理model的参数为空的情况
     *
     * @param null $nameRec
     */
    protected function handleModelNull($nameRec = null)
    {
        $nameArg = $this->argument('name');
        if (is_null($this->option('model'))) { // 处理默认model
            $name = $this->rootNamespace() . 'Models\\' . ($nameRec ?? $nameArg);

            if (class_exists($name) && is_subclass_of($name, \Illuminate\Database\Eloquent\Model::class)) {
                $this->input->setOption('model', $name);
            }else if (is_null($nameRec)){ // 递归查(名称 + Model)的字符串
                $this->handleModelNull($nameArg . 'Model');
            }
        }
    }


    /**
     * 覆盖generator属性
     *
     * @param string $modelName
     */
    protected function output($modelName)
    {
        $this->initResourceGenerator($modelName);

        parent::output($modelName);
        $this->info($this->generator->generateProtected());
    }

    /**
     * 覆盖generator属性
     *
     * @param string $stub
     * @param string $name
     * @return string
     */
    protected function replaceClass($stub, $name)
    {
        $this->initResourceGenerator($this->option('model'));

        $stub = parent::replaceClass($stub, $name);

        return str_replace(
            [
                'DummyProtected',
            ],
            [
                $this->indentCodes($this->generator->generateProtected()),
            ],
            $stub
        );
    }

    protected function initResourceGenerator($modelName)
    {
        $this->generator = new ResourceGenerator($modelName);
        $this->generator->setDisEditBool(!!$this->option('disEdit'));
        $this->generator->setDisSaveBool(!!$this->option('disSave'));
    }

    /**
     * Get the desired class name from the input.
     *
     * @return string
     */
    protected function getNameInput()
    {
        $name = trim($this->argument('name')) . 'AdminController';

        $this->type = $this->qualifyClass($name);

        return $name;
    }

    /**
     * Get the stub file for the generator.
     *
     * @return string
     */
    protected function getStub()
    {
        if ($stub = $this->option('stub')) {
            return $stub;
        }

        if ($this->option('model')) {
            if (!!$this->option('disSave')){ // 不需要form
                return __DIR__ . '/controller.show.stub';
            }

            return __DIR__ . '/controller.stub';
        }

        return __DIR__.'/stubs/blank.stub';
    }
}
<?php
/**
 * Created by PhpStorm.
 * User: code
 * Date: 2019/4/22
 * Time: 19:52
 */

namespace App\Helper\Vendor\LaravelAdmin;

/**
 * 留意在idea中必须\r的换行符
 */
class ResourceGenerator extends \Encore\Admin\Console\ResourceGenerator
{
    /**
     * @var array
     */
    protected $formats = [
        'form_field'  => "\$form->%s('%s', '%s')",
        'show_field'  => "\$show->%s('%s')",
        'grid_column' => "\$grid->column('%s', '%s')",
        'grid_filter'  => "\$filter->%s('%s', '%s')", // grid的filter
        'grid_filter_equal'  => "\$filter->equal('%s', '%s')->%s(%s)", // 上面的特殊情况,要equal来打头
    ];

    /**
     * grid的filter的string的映射
     *
     * @var array
     */
    protected $gridFilterFieldStringTypeMapping = [
        'ip'       => 'ip',
        'email'    => 'email|mail',
        'url'      => 'url|link|src|href',
        'mobile'   => 'mobile|phone',
    ];

    /**
     * grid的filter需要跳出的数组
     *
     * @var array
     */
    protected $gridFilterFieldContinue = [
        'password|pwd',
        'image|img|avatar|pic|picture|cover',
        'file|attachment',
    ];

    /**
     * 不允许编辑,可以新建
     *
     * @var bool
     */
    protected $disEditBool = false;

    /**
     * 不允许保存,(不允许编辑和创建)
     *
     * @var bool
     */
    protected $disSaveBool = false;

    /**
     * 用字段描述做label
     *
     * @param \Doctrine\DBAL\Schema\Column $column
     * @return string|null
     */
    protected function getFormatLabel($column)
    {
        return $this->handleDefaultFieldComment($column);
    }

    /**
     * 处理comment是默认字段时没有写comment,则根据代码配置的返回
     *
     * @param \Doctrine\DBAL\Schema\Column $column
     * @return mixed|string|null
     */
    protected function handleDefaultFieldComment($column)
    {
        $label = $column->getComment();
        $name = $column->getName();

        if (empty($label) && array_key_exists($name, $this->getReservedColumnsMap())) {
            return $this->getReservedColumnsMap()[$name];
        }

        return $label;
    }

    /**
     * 字段对应的中文
     *
     * @see \Encore\Admin\Console\ResourceGenerator::getReservedColumns
     * @return array
     */
    protected function getReservedColumnsMap($datetimeBool = false)
    {
        if ($datetimeBool){ // 只返回时间
            return [
                $this->model->getCreatedAtColumn() => trans('admin.created_at'),
                $this->model->getUpdatedAtColumn() => trans('admin.updated_at'),
                'deleted_at' => '删除时间',
            ];
        }

        return [
            $this->model->getKeyName() => '主键',
            $this->model->getCreatedAtColumn() => trans('admin.created_at'),
            $this->model->getUpdatedAtColumn() => trans('admin.updated_at'),
            'deleted_at' => '删除时间',
        ];
    }

    /**
     * grid的action的模板
     *
     * @return string
     */
    protected function generateGridActions()
    {
        $output = "            \$actions->disableView();";
        $output .= $this->isDisEditBool() ? "\r\n    \$actions->disableEdit();" : '';
        return <<<CODE
\$grid->actions(function (Grid\Displayers\Actions \$actions){
{$output}
        });

CODE;

    }

    /**
     * grid的filter的模板
     *
     * @return string
     * @throws \Exception
     */
    protected function generateGridFilter()
    {
        $eol = "\r\n"; // 会特别在后面加8个空格
        // 用于column
        $filterColumnArr = $rowArr = [];
        $sysDatetimeFilterColumnKeyIterator = new \InfiniteIterator(new \ArrayIterator(['left', 'right']));
        $sysDatetimeFilterColumnBoth = 0;

        foreach ($this->getTableColumns() as $column) {
            $columnName = $column->getName();
            $type = $column->getType()->getName();

            $labelArg = $this->getFormatLabel($column);
            $otherArg = '';
            $fieldFormat = 'grid_filter_equal';
            $fieldType = 'equal';
            $filterColumnKey = 'first';


            // set column fieldType and defaultValue
            switch ($type) {
                case 'boolean':
                case 'bool':
                    $fieldType = 'select';
                    break;
                case 'json': // 暂不过滤json
                    continue;
                case 'string': // 字符串
                    // 跳出
                    foreach ($this->gridFilterFieldContinue as $regex) {
                        if (preg_match("/^($regex)$/i", $columnName) !== 0) {
                            continue;
                        }
                    }

                    // 根据字段名,来匹配类型
                    $matchBool = false;
                    foreach ($this->gridFilterFieldStringTypeMapping as $type => $regex) {
                        if (preg_match("/^($regex)$/i", $columnName) !== 0) {
                            $matchBool = true;
                            $fieldType = $type;
                            break;
                        }
                    }
                    $fieldFormat = $matchBool ? 'grid_filter_equal' : 'grid_filter';
                    break;
                case 'integer':
                case 'bigint':
                case 'smallint':
                case 'timestamp':
                    $fieldType = 'integer';
                    break;
                case 'decimal':
                case 'float':
                case 'real': // 实数
                    $fieldType = 'decimal';
                    break;
                case 'datetime':
                    if (array_key_exists($columnName, $this->getReservedColumnsMap(true))){ // 系统默认时间
                        $filterColumnKey = $sysDatetimeFilterColumnKeyIterator->current();
                        $sysDatetimeFilterColumnKeyIterator->next();
                        $rowArr[$filterColumnKey] = 2;
                        ++$sysDatetimeFilterColumnBoth;
                    }

                    $fieldType = 'datetime';
                    break;
                case 'date':
                    $fieldType = 'date';
                    break;
                case 'time':
                    $fieldType = 'time';
                    break;
                case 'text':
                case 'blob':
                    $fieldType = 'textarea';
                    break;
            }

            if ($fieldFormat === 'grid_filter_equal'){
                $row = '    ' . sprintf($this->formats[$fieldFormat], $columnName, $labelArg, $fieldType, $otherArg) . ";{$eol}";
            }else{
                $row = '    ' . sprintf($this->formats[$fieldFormat], $fieldType, $columnName, $labelArg) . ";{$eol}";
            }

            // 处理column,所有
            $filterColumnArr[$filterColumnKey][] = $row;

        } // foreach结束
        $filterCode = '';

        // 拼接column
        foreach ($filterColumnArr as $key => $filterColumnItemArr) {
            if ($sysDatetimeFilterColumnBoth < 2){ // 时间搜索不够2个,就不用column
                $filterCode .= join('', $filterColumnItemArr);
                continue;
            }
            $width = isset($rowArr[$key]) ? '1/' . $rowArr[$key] : 12; // 整行的时候要设置为12

            $filterCode .= $this->generateGridFilterColumn($width, trim(join('    ', $filterColumnItemArr), $eol));
        }

        if ($sysDatetimeFilterColumnBoth < 2){
            $filterCode = rtrim($filterCode, $eol);
        }

        // 留意空格对齐
        $output =  <<<CODE
        \$grid->filter(function (Grid\Filter \$filter){
            \$filter->disableIdFilter();
        {$filterCode}
        });

CODE;

        return $output;
    }

    protected function generateGridFilterColumn($width, $filterColumnString)
    {
        return <<<CODE
        
            \$filter->column({$width}, function (Grid\Filter \$filter){
            {$filterColumnString}
            });
CODE;

    }

    /**
     * grid的代码
     *
     * @return string
     * @throws \Exception
     */
    public function generateGrid()
    {
        $output = '';

        // 处理禁用创建按钮
        if ($this->isDisSaveBool()){
            $output .= "\$grid->disableCreateButton();\r\n";
        }

        $output .= $this->generateGridActions();
        $output .= $this->generateGridFilter();
        $output .= "\r\n";

        foreach ($this->getTableColumns() as $column) {
            $name = $column->getName();

            $output .= sprintf($this->formats['grid_column'], $name, $this->getFormatLabel($column));
            $output .= ";\r\n";
        }

        return $output;
    }

    /**
     * form的代码
     *
     * @return string
     * @throws \Exception
     */
    public function generateForm()
    {
        $reservedColumns = $this->getReservedColumns();

        $output = '';

        foreach ($this->getTableColumns() as $column) {
            $name = $column->getName();
            $type = $column->getType()->getName();
            $default = $column->getDefault();

            // 默认元素只显示不修改
            if (in_array($name, $reservedColumns)) {
                $type = 'display';
            }
            $defaultValue = '';

            // set column fieldType and defaultValue
            switch ($type) {
                case 'display': // 只显示
                    $fieldType = 'display';
                    break;


                case 'boolean':
                case 'bool':
                    $fieldType = 'switch';
                    break;
                case 'json':
                    if (\Encore\Admin\Form::findFieldClass('json')) { // 支持json输出
                        $fieldType = 'json';
                        break;
                    }
                    $fieldType = 'text';
                    break;
                case 'array':
                case 'object':
                    $fieldType = 'text';
                    break;
                case 'string':
                    $fieldType = 'text';
                    foreach ($this->fieldTypeMapping as $type => $regex) {
                        if (preg_match("/^($regex)$/i", $name) !== 0) {
                            $fieldType = $type;
                            break;
                        }
                    }
                    $defaultValue = "'{$default}'";
                    break;
                case 'integer':
                case 'bigint':
                case 'smallint':
                case 'timestamp':
                    $fieldType = 'number';
                    break;
                case 'decimal':
                case 'float':
                case 'real':
                    $fieldType = 'decimal';
                    break;
                case 'datetime':
                    $fieldType = 'datetime';
                    $defaultValue = "date('Y-m-d H:i:s')";
                    break;
                case 'date':
                    $fieldType = 'date';
                    $defaultValue = "date('Y-m-d')";
                    break;
                case 'time':
                    $fieldType = 'time';
                    $defaultValue = "date('H:i:s')";
                    break;
                case 'text':
                case 'blob':
                    $fieldType = 'textarea';
                    break;
                default:
                    $fieldType = 'text';
                    $defaultValue = "'{$default}'";
            }

            $defaultValue = $defaultValue ?: $default;

            $output .= sprintf($this->formats['form_field'], $fieldType, $name, $this->getFormatLabel($column));

            if (trim($defaultValue, "'\"")) {
                $output .= "->default({$defaultValue})";
            }

            $output .= ";\r\n";
        }

        return $output;
    }

    /**
     * 返回类属性
     *
     * @return string
     */
    public function generateProtected()
    {
        $output = <<<CODE

    /**
     *
     * 页名
     *
     * @var string
     */
    protected \$headerText = '';
CODE;

        return $output;
    }

    /**
     * @return bool
     */
    public function isDisEditBool(): bool
    {
        return $this->disEditBool;
    }

    /**
     * @param bool $disEditBool
     * @return ResourceGenerator
     */
    public function setDisEditBool(bool $disEditBool = true)
    {
        $this->disEditBool = $disEditBool;

        return $this;
    }

    /**
     * @param bool $disSaveBool
     * @return ResourceGenerator
     */
    public function setDisSaveBool(bool $disSaveBool): ResourceGenerator
    {
        $this->disSaveBool = $disSaveBool;
        if ($disSaveBool) { // 也同时禁用create
            $this->setDisEditBool($disSaveBool);
        }

        return $this;
    }

    /**
     * @return bool
     */
    public function isDisSaveBool(): bool
    {
        return $this->disSaveBool;
    }
}
<?php
/**
 * Created by PhpStorm.
 * User: code
 * Date: 2019/4/24
 * Time: 14:49
 */

namespace App\Admin\Extensions\Form;

/**
 * @example
        $form->asyncRender('async-json', function (Form $form)use($tinyint){
            $output = '';
            if ($form->builder()->isEditing()) { // 编辑
                $output .= $form->hidden('type', '分类')->default($data['type'])->render()->render();
            }else{ // 创建
                $output .= $form->hidden('type', '分类')->default($type)->render()->render();
            }

            return $output;
        });

 rules好像是失效了
 */


/**
 * 传递匿名函数,实现后续render
 * 用于解决在控制器判断创建和编辑的问题
 */
class AsyncRender extends \Encore\Admin\Form\Field
{
    protected $callback;

    public function __construct($column, $arguments = [])
    {
        $this->column = $column;
        $this->id = $this->formatId($column);

        // 第一个参数为回调函数,第二个为form对象
        $callback = $arguments[0];
        /** @var \Encore\Admin\Form $form */
        $form = $arguments[1];
        // 处理无法识别编辑的问题
        $form->saving(function (\Encore\Admin\Form $form){

            if ($form->model()->getKey()) { // 指定id是编辑
                $form->model()->exists = true;
            }
        });

        if ($callback && $callback instanceof \Closure) {
            $this->with($callback);

        }
    }

    public function with(\Closure $callback)
    {
        $this->callback = $callback;
    }

    public function render()
    {
        if ($this->callback instanceof \Closure) {
            return call_user_func($this->callback, $this->form);
        }

        return '';
    }

}
<?php

namespace App\Admin\Extensions\Column;

use Encore\Admin\Admin;
use Encore\Admin\Grid\Displayers\AbstractDisplayer;

/**
 * 官方示例
 * 用于覆盖原有laravel-admin里的expand,原有的只有一个下箭头,这个多个文案
 * 留意第一个参数的匿名函数,没有参数,$this为当前model
 */
class ExpandRow extends AbstractDisplayer
{
    public function display(\Closure $callback = null, $btn = '查看')
    {
        $callback = $callback->bindTo($this->row);

        $html = call_user_func($callback);

        $script = <<<EOT

$('.grid-expand').on('click', function () {
    if ($(this).data('inserted') == '0') {
        var key = $(this).data('key');
        var row = $(this).closest('tr');
        var html = $('template.grid-expand-'+key).html();

        row.after("<tr><td></td><td colspan='"+(row.find('td').length-1)+"' style='padding:0 !important; border:0px;'>"+html+"</td></tr>");

        $(this).data('inserted', 1);
    }

    $("i", this).toggleClass("fa-caret-right fa-caret-down");
});
EOT;
        Admin::script($script);

        $btn = $btn ?: $this->column->getName();

        $key = $this->getKey();

        return <<<EOT
<a class="btn btn-xs btn-default grid-expand" data-inserted="0" data-key="{$key}" data-toggle="collapse" data-target="#grid-collapse-{$key}">
    <i class="fa fa-caret-right"></i> $btn
</a>
<template class="grid-expand-{$key}">
    <div id="grid-collapse-{$key}" class="collapse">$html</div>
</template>
EOT;
    }
}
<?php

if (!function_exists('getAdminStorageFullUrl')) {
    /**
     * 获取laravel-admin的图片完整路径
     *
     * @param string $path 路径
     * @return string
     */
    function getAdminStorageFullUrl($path)
    {
        if (empty($path)) {
            return '';
        }
        
        return \Illuminate\Support\Facades\Storage::disk(config('admin.upload.disk'))->url($path);
    }
}

以上是关于php laravel管理员相关类库的主要内容,如果未能解决你的问题,请参考以下文章

php laravel里缓存相关类库的修改

php laravel的API版本管理相关类

laravel 如何引入自己的函数或类库

php ThinkPHP相关类库

php 碳类库的相关代码

php swoft的模型相关类库强化