奇怪的学说实体行为

时间:2017-01-23 05:35:27

标签: symfony doctrine-orm twig

我有两个实体,Invoice和InvoiceItem在yml中定义如下。

Invoice.orm.yml

AppBundle\Entity\Invoice:
type:   entity
table:  invoices
repositoryClass:   AppBundle\Repository\InvoiceRepository
fields:
    id:
        id: true
        type: integer
        generator:
            strategy:   AUTO
    ......

oneToMany:
  items:
    targetEntity: InvoiceItem
    mappedBy: invoice
  deductions:
    targetEntity: InvoiceDeduction
    mappedBy: invoice
  payments:
    targetEntity: InvoicePayment
    mappedBy: invoice

InvoiceItem.orm.yml

AppBundle\Entity\InvoiceItem:
type:   entity
table:  invoice_items
repositoryClass:   AppBundle\Repository\InvoiceItemRepository
fields:
    id:
        id: true
        type: integer
        generator:
            strategy:   AUTO
....
manyToOne:
  invoice:
    targetEntity: Invoice
    inversedBy: items
    joinColumn:
      invoice_id:
        referencedColumnName: id
      onDelete: CASCADE

我的控制器收到发票详细信息并保存元素,如下所示

public function createInvoiceAction(Request $request)
{
    ....
    $invoice = new Invoice();
    $invoice->setReference($ref);
    $invoice->setInvoiceDate(\DateTime::createFromFormat('d/m/Y',$request->query->get('invoiceDate')));
    $invoice->setDescription($request->query->get('summary'));
    $invoice->setAttn($request->query->get('att'));
    $invoice->setIsVatable($request->query->get('vattable') == 'true' ? 1 : 0);
    $invoice->setAdditionalInstructions($request->query->get('additional'));
    $invoice->setJob($job);
    $invoice->setCurrency($request->query->get('currency'));
    $invoice->setGeneratedBy($createdBy);
    $invoice->setFile($filename);
    $job->setStatus('Invoiced');
    $em->persist($invoice);
    $em->persist($job);
    $em->flush();

    $items = $request->query->get('items');
    for($i=0;$i<count($items);$i++)
    {
      if($items[$i]['description']!= '' && $items[$i]['amount'] != '')
      {
        $item = new InvoiceItem();
        $item->setDescription($items[$i]['description']);
        $item->setAmount($items[$i]['amount']);
        $item->setInvoice($invoice);
        $em->persist($item);
        $em->flush();
      }
    }

    $deductions = $request->query->get('deductions');
    for($i=0;$i<count($deductions);$i++)
    {
      if($deductions[$i]['description'] != '' && $deductions[$i]['value'] != '')
      {
        $deduction = new InvoiceDeduction();
        $deduction->setDescription($deductions[$i]['description']);
        $deduction->setValue($deductions[$i]['value']);
        $deduction->setIsPercentage($deductions[$i]['isPercentage'] == 'true' ? 1 : 0);
        $deduction->setInvoice($invoice);
        $em->persist($deduction);
        $em->flush();
      }
    }

    $html = $this->renderView('AppBundle:Default:invoice.html.twig', array('invoice' => $invoice));

    return new Response(
        $html
    );
}

invoice.html.twig,用于显示发票明细,包括项目和扣除。

.....

{% for item in invoice.items %}
    <tr>
      <td>{{ loop.index }}</td>
      <td>{{ item.description }}</td>
      <td>{{ item.amount|number_format(0, '', ',') }}</td>
     </tr>
{% endfor %}
.....

我遇到的挑战是发送到模板的$ invoice对象没有应该是集合的项目或推论。我已经检查了数据库并且可以确认项目和扣除是否持久保存到相应的表中,所以我不明白为什么表中没有invoice.items或invoice.deductions。

出于绝望,我在每个InvoiceItem对象创建后都认为可能在持久化事务完成之前呈现模板但是这也没有帮助。

1 个答案:

答案 0 :(得分:0)

<强>更新

我发现的另一个错误是在joinColumn下定义的onDelete选项。它应该是:

manyToOne:
  invoice:
    targetEntity: Invoice
    inversedBy: items
    joinColumn:
      invoice_id:
        referencedColumnName: id
    onDelete: CASCADE

<强> --------

如果仅在createInvoiceAction期间呈现视图时遇到此问题,则问题可能是因为您实际上没有通过名为addItem()之类的方法将InvoiceItem添加到Invoice对象(命名取决于您如何命名发票实体中的关系),这些项目可能只会在您下次查询发票时出现在发票实体中,因为即使您已设置每个项目的发票,也可能是这些实体刚刚创建,doctrine可能无法使用代理类检索它们。所以解决方案很简单:在发票实体上使用addItem方法将项目添加到发票中,然后不要忘记在该方法中添加为给定项目设置发票的逻辑

public function addItem(InvoiceItem $item)
{
    $item->setInvoice($this);
    $this->items[] = $item;

    return $this;
}

但是,如果下次查询已经保留的发票及其项目时仍然存在此问题,我建议您检查该对象是否实际包含getter方法,而不是简单地尝试通过公共财产。换句话说,在发票类中,名为items的属性应该被定义为private,并且您应该有一个getItems()方法来检索这些项。 与doctrine一起使用的对象必须具有这些方法,因为它使用其代理类覆盖这些方法中的逻辑,以便添加代码,这些代码也会发送查询以在您的情况下从数据库和地点检索InvoiceItem。它们位于对象的私有属性中,然后才在您的类中运行getter代码。如果没有这些方法,私有属性将保持为空,因为没有其他方式可以让学说为您从数据库中检索它们(除非可能是fetch:“EAGER”)。