laravel-admin 之 form

wozailu發表於2021-04-16

__call 魔術方法使用

這個方法用來監視一個物件中的其它方法。如果你試著呼叫一個物件中不存在的方法,__call 方法將會被自動呼叫。

會省略部分程式碼,只挑取要講解的內容

Layout

  • 佈局設定
    /**
     * Add a new column in layout.
     *
     * @param int      $width
     * @param \Closure $closure
     */
    public function column($width, \Closure $closure)
    {
        if ($this->columns->isEmpty()) {
            $column = $this->current;

            $column->setWidth($width);
        } else {
            $column = new Column($width);

            $this->current = $column;
        }

        $this->columns->push($column);

        $closure($this->parent);
    }
$content->row(function(Row $row) {
    $row->column(4, 'foo');
    $row->column(4, 'bar');
    $row->column(4, 'baz');
});
----------------------------------
|foo       |bar       |baz       |
|          |          |          |
|          |          |          |
|          |          |          |
|          |          |          |
|          |          |          |
----------------------------------

Column

  • row 獲取內容
  • build 渲染輸出
    /**
     * Add a row for column.
     *
     * @param $content
     *
     * @return Column
     */
    public function row($content)
    {
        if (!$content instanceof \Closure) {
            $row = new Row($content);
        } else {
            $row = new Row();

            call_user_func($content, $row);
        }

        ob_start();

        $row->build();

        $contents = ob_get_contents();

        ob_end_clean();

        return $this->append($contents);
    }

    /**
     * Build column html.
     */
    public function build()
    {
        $this->startColumn();

        foreach ($this->contents as $content) {
            if ($content instanceof Renderable || $content instanceof Grid) {
                echo $content->render();
            } else {
                echo (string) $content;
            }
        }

        $this->endColumn();
    }
  • 例子

ArticleController

protected function form()
{
    $form = new Form(new Article());
    $form->image('image', __('Image'));
    return $form;
}

Form

  • 欄位呼叫實現
    • row 鏈式呼叫
class Form implements Renderable
{
    use HasFields;

    public function __call($method, $arguments)
    {
        if ($className = static::findFieldClass($method)) { // 查詢欄位是否有對應的類
            $column = Arr::get($arguments, 0, ''); //[0];

            $element = new $className($column, array_slice($arguments, 1)); // 例項化

            $this->pushField($element);

            return $element;
        }
    }

     /**
     * Add a row in form.
     *
     * @param Closure $callback
     *
     * @return $this
     */
    public function row(Closure $callback): self
    {
        $this->rows[] = new Row($callback, $this);

        return $this;
    }
}

HasFields

  • 定義欄位和類對應
/**
 * 這裡的註釋IDE 會識別提示
 *
 * @method Field\Image           image($column, $label = '')
 */
trait HasFields
{
    /**
     * Available fields.
     *
     * @var array
     */
    public static $availableFields = [
        'image'             => Field\Image::class,
    ];
}

Image

  • 前面設定的各種引數在這裡渲染
public function render()
{
    return Admin::component($this->getView(), $this->variables());
}

HasAssets

  • 渲染的具體實現
    1. 渲染結果
    2. 分析html
    3. 對 html dom 樹分析插入需要的程式碼
    4. 返回渲染後的字串
trait HasAssets
{
    /**
     * @param $component
     */
    public static function component($component, $data = [])
    {
        $string = view($component, $data)->render();

        $dom = new \DOMDocument();

        libxml_use_internal_errors(true);
        $dom->loadHTML('<?xml encoding="utf-8" ?>'.$string);
        libxml_use_internal_errors(false);
    }
}

helpers

助手函式

  • view 獲取例項,解析內容
  • render 獲取內容

if (! function_exists('view')) {
    /**
     * Get the evaluated view contents for the given view.
     *
     * @param  string|null  $view
     * @param  \Illuminate\Contracts\Support\Arrayable|array   $data
     * @param  array   $mergeData
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
     */
    function view($view = null, $data = [], $mergeData = [])
    {
        $factory = app(ViewFactory::class);

        if (func_num_args() === 0) {
            return $factory;
        }

        return $factory->make($view, $data, $mergeData);
    }
}

form.blade.php

  • row 呼叫渲染
  • columns 呼叫渲染
<div class="box-body">
        @if(!$tabObj->isEmpty())
            @include('admin::form.tab', compact('tabObj'))
        @else
            <div class="fields-group">

                @if($form->hasRows())
                    @foreach($form->getRows() as $row)
                        {!! $row->render() !!}
                    @endforeach
                @else
                    @foreach($layout->columns() as $column)
                        <div class="col-md-{{ $column->width() }}">
                            @foreach($column->fields() as $field)
                                {!! $field->render() !!}
                            @endforeach
                        </div>
                    @endforeach
                @endif
            </div>
        @endif

    </div>
    <!-- /.box-body -->
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章