将自定义方法添加到 Laravel 模型会导致 create() 忽略属性
Adding custom method to Laravel model causes create() to ignore attributes
在 Laravel 8 中,我已经有了可用的 DocumentPdf
资源 - 至少我能够使用 DocumentPdf::create($attributes)
.
创建对象
现在我想在模型中创建一个自定义方法,一个将用 $data
填充文档并将其发送到浏览器的方法。虽然它适用于现有文档,但添加方法会破坏 create()
,这样当我发送填写好的表格时,我会收到 Illuminate\Database\QueryException
:
SQLSTATE[HY000]: General error: 1364 Field 'filename' doesn't have a default value (SQL: insert into document_pdfs
(updated_at
, created_at
) values (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
,并有一个父抽象 class Document
将由 DocumentController
.
处理
fill
是Model方法,填充Model的属性。你不应该覆盖它;将您的方法名称更改为其他名称。
Illuminate\Database\Eloquent\Builder@create
使用传递的数据创建模型的新实例,它将调用 fill
来填充模型的属性。
在 Laravel 8 中,我已经有了可用的 DocumentPdf
资源 - 至少我能够使用 DocumentPdf::create($attributes)
.
现在我想在模型中创建一个自定义方法,一个将用 $data
填充文档并将其发送到浏览器的方法。虽然它适用于现有文档,但添加方法会破坏 create()
,这样当我发送填写好的表格时,我会收到 Illuminate\Database\QueryException
:
SQLSTATE[HY000]: General error: 1364 Field 'filename' doesn't have a default value (SQL: insert into
document_pdfs
(updated_at
,created_at
) values (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
,并有一个父抽象 class Document
将由 DocumentController
.
fill
是Model方法,填充Model的属性。你不应该覆盖它;将您的方法名称更改为其他名称。
Illuminate\Database\Eloquent\Builder@create
使用传递的数据创建模型的新实例,它将调用 fill
来填充模型的属性。