【问题标题】:Adding custom method to Laravel model causes create() to ignore attributes向 Laravel 模型添加自定义方法会导致 create() 忽略属性
【发布时间】:2021-02-04 23:16:49
【问题描述】:

在 Laravel 8 中,我已经有一个可用的 DocumentPdf 资源 - 至少我能够使用 DocumentPdf::create($attributes) 创建对象。

现在我想在模型中创建一个自定义方法,该方法将用$data 填充文档并将其发送到浏览器。虽然它适用于现有文档,但添加该方法会破坏create(),当我发送填写好的表格时,我会收到Illuminate\Database\QueryException

SQLSTATE[HY000]:一般错误:1364 字段“文件名”没有默认值(SQL:插入document_pdfsupdated_atcreated_at)值(2020-10-22 02:42 :26, 2020-10-22 02:42:26))

这不是模型中的第一个自定义方法,而是唯一的突破性方法 - 注释掉该方法使 create() 再次工作,但随后我失去了填写文档的能力。

app/DocumentPdf.php:

namespace App;

use Illuminate\Database\Eloquent\Model;
use mikehaertl\pdftk\Pdf;

class DocumentPdf extends Model
{
    // (... some constants, static methods and relations ...)

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $guarded = [];

    /**
     * Checks whether the document is active
     *
     * @return bool
     */
    public function isActive()
    {
        return $this->active;
    }

    /**
     * Get full path to the file
     *
     * @return string
     */
    public function fullpath()
    {
        return storage_path('app' . DIRECTORY_SEPARATOR . $this->path);
    }

    /**
     * Fill the document and send it to browser
     *
     */
    public function fill(array $data)
    {
        $pdf = new Pdf($this->fullpath());
        $pdf->fillForm($data)
            ->needAppearances()
            ->send(date('YmdHis') . '.pdf');
    }

app/Http/Controllers/DocumentPdfController.php:

namespace App\Http\Controllers;

use App\DocumentPdf;
use Illuminate\Http\Request;
use mikehaertl\pdftk\Pdf;

class DocumentPdfController extends Controller
{
    // (...)

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('documents.create');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->authorize('create', DocumentPdf::class);

        DocumentPdf::create($this->validateFormAndStoreFile());

        return redirect(route('documents.index'))
            ->with('model-message', 'Document created');
    }

    // (...)

    /**
     * Validate and parse data for storing/updating the resource.
     *
     * @return Array
     */
    protected function validateFormAndStoreFile()
    {
        $form = $this->validateForm();
        $form += $this->storeFile();
        $form += $this->discoverFields($form['path']);
        unset($form['file']);

        return $form;
    }

    /**
     * Validate data for storing/updating the resource.
     *
     * @return Array
     */
    protected function validateForm()
    {
        return request()->validate([
            'display_name' => 'nullable|max:255',
            'description' => 'nullable',
            'file' => 'required|file|mimes:pdf',
        ]);
    }

    /**
     * Parse data for storing/updating the resource in database.
     *
     * @return Array
     */
    protected function storeFile()
    {
        $path = request('file')->store('documents');

        $form = [
            'filename' => request('file')->getClientOriginalName(),
            'extension' => request('file')->extension(),
            'size' => request('file')->getSize(),
            'mimetype' => request('file')->getMimeType(null),
            'path' => $path
        ];

        return $form;
    }


    /**
     * Discover PDF file fields.
     * Todo: I feel like it should be handled in DocumentPdf model
     *      but failed to do so due to BadMethodCallException - to be verified
     *
     * @return Array
     */
    protected function discoverFields($filename)
    {
        $pdf = new Pdf(storage_path('app' . DIRECTORY_SEPARATOR . $filename));
        return [
            'fields' => json_encode($pdf->getDataFields()),
        ];
    }

我怎样才能定义这样的方法不破坏现有的功能?我想将它放在模型中,因为将来我计划处理其他类型的文档,例如。 G。 DocumentXls,并有一个父抽象类 Document 将由 DocumentController 处理。

【问题讨论】:

标签: php laravel eloquent model laravel-8


【解决方案1】:

fill是一个Model方法,填充Model的属性。你不应该覆盖它;将您的方法名称更改为其他名称。

Illuminate\Database\Eloquent\Builder@create 使用传递的数据创建模型的新实例,该实例将调用fill 来填充模型的属性。

【讨论】:

  • 哦...当然可以,谢谢!如果可以的话,我会投票给你 :) 编辑:现在我可以了!
猜你喜欢
  • 2013-06-18
  • 2015-12-01
  • 2020-11-23
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 2011-02-18
  • 1970-01-01
  • 2013-04-15
相关资源
最近更新 更多