我有一个很奇怪的情况。我有一段代码,过去从未出现任何问题。从昨晚开始,它的行为就这样。
在更新模型之前,该模型的ID为true。下面的函数来自控制器,并通过POST请求进行调用。该请求得到验证,并且当尚未导出模型时,它将导出到另一个系统。如果导出成功,则将使用适当的值更新模型。在此过程的任何阶段都不会设置ID。
我已经在代码中添加了注释,以使您了解发生的情况。
public function export(Request $request, VeniceService $service, Invoice $invoice)
{
$invoice = $invoice->load([
'user', 'customer', 'extension.referenceValues.definition', 'lines'
]);
$this->enforce([
new CheckCstNum($invoice->customer),
new CheckReferences($invoice->extension),
], 432);
if ($invoice->to_export) {
DB::beginTransaction();
try {
var_dump($invoice->id); // returns the id
$data = $service->export($invoice);
var_dump($invoice->id); // returns the true
$invoice->book_date = Carbon::now();
$invoice->doc_num = $data['doc_num'];
$invoice->sys_num = $data['sys_num'];
$invoice->tsm_num = $data['tsm_num'];
$invoice->to_export = false;
$invoice->is_ticked = false;
var_dump($invoice->id); // This returns true
var_dump($invoice); // All the values are correct, except the id, this is set to true
$invoice->save(); // With the id as true, this throws an exception. Duplicate entries for PRIMARY key id, '1'
DB::commit();
$service->attachPdf($invoice, Printer::print($invoice)->output());
} catch (VeniceException $e) {
DB::rollBack();
return $e->render($request);
} catch (\Exception $e) {
DB::rollBack();
return response()->json($e->getMessage(), 500);
}
}
return new InvoiceResource($invoice->refresh()); // returns the invoice, but the id is still true
}
$this->service->export()
解析为该功能。在此之前,该ID仍然是模型的原始ID。
public function export($model)
{
return $this->call($model, __FUNCTION__);
}
protected function call($model, $function)
{
$class = $this->getClassName($model);
$method = "{$function}{$class}";
return $this->$method($model);
}
public function exportInvoice($invoice)
{
var_dump($invoice->id); // Returns the id
$veniceInvoice = (new VeniceInvoiceResource($invoice))->toArray(request());
var_dump($invoice->id); // Returns true...
return $this->request('POST', 'venice/invoices/' . $this->bookSales, [
RequestOptions::JSON => $veniceInvoice
]);
}
$veniceInvoice = (new VeniceInvoice($invoice))->toArray(request());
在此行之后,将id设置为true。这确实没有意义,因为它一直有效,并且该模型不会以任何方式被操纵。
最后一段代码。但是我认为这与问题无关。
VeniceInvoiceResource.php
public function toArray($request)
{
$pdf = Printer::print($this->resource)->output();
$lines = $this->customer->standard_base == 10 ? VeniceInvoiceLineIC::collection($this->lines) : VeniceInvoiceLine::collection($this->lines);
$refs = $this->extension->referenceValues->map(function ($item) {
return [
'index' => 0,
'quantity' => 0,
'unit_price' => 0,
'description' => $item->definition->name . ' ' . $item->value,
'vat_code' => 0,
'ic_code' => 0,
];
})->toArray();
$details = array_merge($refs, $lines->toArray($request));
return [
'cst_num' => $this->customer->cst_num,
'book' => ($this->book === 'VKPCN') ? $this->book : config('venice.config.sales.book'),
'amount' => $this->total,
'vat_amount' => $this->total,
'exp_date' => carbon(config('venice.config.sales.date'))->addDays($this->customer->exp_term)->format('d/m/Y'),
'doc_date' => carbon(config('venice.config.sales.date'))->format('d/m/Y'),
'vat_system' => $this->customer->vat_system,
'bf_code' => $this->customer->bf_code,
'doc_type' => ($this->doc_type === 'slsCreditnote') ? 1 : 0,
'pdf' => base64_encode($pdf),
'pdfName' => $this->date->format('Ym') . '-' . $this->id . '.pdf',
'remark' => 'Clockwork ' . $this->date->format('Y F') . ' ' . $this->user->name,
'details' => $details,
];
}
目前,我已经添加了一个临时修复程序来缓解此问题。我创建了$发票的副本。以后,我将原始发票的ID设置为克隆的发票ID。
...
$invoice_copy = clone $invoice;
if ($invoice->to_export) {
DB::beginTransaction();
try {
$data = $service->export($invoice);
$invoice->book_date = Carbon::now();
$invoice->doc_num = $data['doc_num'];
$invoice->sys_num = $data['sys_num'];
$invoice->tsm_num = $data['tsm_num'];
$invoice->to_export = false;
$invoice->is_ticked = false;
$invoice->id = $invoice_copy->id;
$invoice->save();
DB::commit();
...
经过大量调试后,我查明了将id设置为true的位置。我仍然不知道为什么。
在生成PDF之前的VeniceInvoiceResource $this->id
中,该ID仍然是原始发票ID。在打印机之后,标识为true
。
如果我查看在Illuminat\Http\Resources\JsonResource
(资源扩展JsonResource)中找到的资源构造函数,我会看到$this->resource
设置为传入值,在这种情况下为$invoice
。
/**
* Create a new resource instance.
*
* @param mixed $resource
* @return void
*/
public function __construct($resource)
{
$this->resource = $resource;
}
在VeniceInvoiceResource
中,$ this->资源被传递到Printer实例。在资源$this
中还具有发票的值。
/**
* Load items to print.
*
* @param $items
* @return $this
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function print($items, $toPrint = null)
{
$items = is_array($items) || $items instanceof Collection ? $items : func_get_args();
foreach ($items as $item) {
if ($item instanceof Printable) {
foreach ($item->printData($toPrint) as $key => $data) {
switch($key) {
case 'merge':
$this->mergeOutput($data);
break;
case 'mergeFile':
$this->mergeFile($data);
break;
default:
$this->toPrint[] = $this->view->make($key, $data)->render();
}
}
} elseif ($item instanceof Renderable) {
$this->toPrint[] = $item->render();
} elseif (is_string($item)) {
$this->toPrint[] = $item;
} else {
throw new \InvalidArgumentException('Invalid argument');
}
}
return $this;
}
在打印方法中,在这种情况下使用$this->toPrint[] = $this->view->make($key, $data)->render();
。输出方法如下所示。
/**
* Get the output as string.
*
* @return string
* @throws \iio\libmergepdf\Exception
*/
public function output()
{
return $this->generate();
}
/**
* Generate and merge.
*
* @return string
* @throws \iio\libmergepdf\Exception
*/
protected function generate()
{
$data = !empty($this->toPrint) ? $this->toPrint : [''];
$result = $this->pdf->getOutputFromHtml($data);
if (!empty($this->toMerge)) {
$this->merger->addRaw($result);
foreach ($this->toMerge as $item) {
$this->merger->addRaw($item);
}
$result = $this->merger->merge();
}
$this->toPrint = null;
$this->toMerge = null;
return $result;
}
在打印服务中,没有任何操作,它只是将集合和项目打印为PDF格式。
最后一次编辑,因为我找到了导致所有这一切的行。但是我不完全理解为什么它将id设置为true。
在Printer::print
中,有一个对模型上方法的调用,printData()
该方法具有if语句来解决我们遇到的两张发票需要特殊处理的问题。时间不多,因此我们决定使用简单的if语句足以应付这种情况。
if ($this->id = 4128 || $this->id === 4217) {
$vat_amount = 0;
$vat_label = '';
}
如果仔细观察,您会发现第一个条件不是条件...存在问题,并且修复很简单。删除此if语句,因为我们不再需要它。发票4128 & 4217
已被打印并存档。它们不再需要处理。
答案 0 :(得分:2)
好像您在printData()
方法中发现了问题。
为什么id
最终以true
结束,这是由于operator precedences的不同所致。
比较运算符(===
)的优先级高于逻辑运算符(||
),因此在逻辑比较之前进行比较。因此,如果比较运算符正确,那么就可以运行该程序(为清楚起见添加了括号):
($this->id === 4128) || ($this->id === 4217)
但是,因为第一个运算符实际上是赋值而不是比较,所以这改变了操作顺序。比较运算符和逻辑运算符的优先级高于赋值运算符,因此它们首先被执行。这是实际运行的内容(为清晰起见添加了括号):
$this->id = (4128 || $this->id === 4217)
因此,id
被分配给逻辑比较的结果。由于所有非零数字的求值为true
,因此逻辑比较的求值为true
,因此id
被设置为true
。