Symfony 教条主义者不为自己的实体工作

Symfony 教条主义者不为自己的实体工作,symfony,orm,doctrine-orm,Symfony,Orm,Doctrine Orm,我有客户,产品,预算和预算项目实体预算与@ORM\manytone与客户相关,与@ORM\OneToMany与预算项相关预算项与产品和预算关联为@ORM\manytone 在BudgetItem中,有一种方法可用于计算先前选择的产品的总价格,然后将其保存到预算项目表中。更新项目时,将执行代码并再次成功地将其保存到数据库中。方法如下: public function calculateTotalPrice() { return $this->getProduct()->getP

我有
客户
产品
预算
预算项目
实体<代码>预算与@ORM\manytone
客户
相关,与@ORM\OneToMany
预算项
相关<代码>预算项与
产品
预算
关联为@ORM\manytone

BudgetItem
中,有一种方法可用于计算先前选择的
产品的总价格,然后将其保存到
预算项目
表中。更新项目时,将执行代码并再次成功地将其保存到数据库中。方法如下:

public function calculateTotalPrice()
{
    return $this->getProduct()->getPrice() * $this->getMeters();
}

/**
 * @ORM\PrePersist
 */
public function onPreEvents()
{
    $this->setPrice($this->calculateTotalPrice());
}
现在,我有了
预算

/**
 * @return \DateTime
 */
public function generateNextPaymentDate()
{
    if ($this->getStartsAt() !== null) {
        $date = new \DateTime($this->getStartsAt()->format('Y-m-d'));
        return $date->add(new \DateInterval('P' . $this->getCheckFor() . 'D'));
    }
}

/**
 * @return decimal
 */
public function calculateTotalBudgetPrice()
{
    $totalBudgetPrice = 0;

    foreach ($this->getItems() as $item) {
        $totalBudgetPrice += $item->getPrice();
    }

    return $totalBudgetPrice;
}

/**
 * @return decimal
 */
public function calculateInstallmentRatePrice()
{
    return $this->calculateTotalBudgetPrice() / $this->getInstallmentRate();
}

/**
 * @ORM\PrePersist
 */
public function onPreEvents()
{
    $this->setNextPaymentDate($this->generateNextPaymentDate());
    $this->setInstallmentRatePrice($this->calculateInstallmentRatePrice());
    $this->setTotalBudgetPrice($this->calculateTotalBudgetPrice());
}
在编辑
预算
后,所有这些方法的结果都不会保留到数据库中。如果我理解得很好,Doctrine2似乎不会更新其他相关实体,但这些字段属于该实体。我还需要做什么

编辑

BudgetController
,我在其中持久化并刷新

<?php

namespace CDGBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use CDGBundle\Entity\Budget;
use CDGBundle\Form\BudgetType;

class BudgetController extends Controller
{
    /**
     * Lista todos os orçamentos
     */
    public function indexAction()
    {
        return $this->render('budget/index.html.twig', array(
            'budgets' => $this->getDoctrine()->getRepository('CDGBundle:Budget')->findAll(),
            'title' => 'Lista de Orçamentos'
        ));
    }

    /**
     * Adicionar um novo orçamento
     * 
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
     */
    public function addAction(Request $request)
    {
        $budget = new Budget();
        $form = $this->createForm(new BudgetType(), $budget);
        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($budget);
            $em->flush();

            return $this->redirectToRoute('budgets');
        }

        return $this->render('budget/add.html.twig', array(
            'form' => $form->createView(),
            'title' => 'Novo Orçamento'
        ));
    }

    /**
     * Exibe os detalhes do orçamento selecionado
     * 
     * @param integer $id
     * @return Budget
     */
    public function showAction($id)
    {
        $budget = $this->getDoctrine()->getRepository('CDGBundle:Budget')->find($id);

        return $this->render('budget/show.html.twig', array(
            'budget' => $budget,
            'title' => 'Dados do orçamento #' . $budget->getId()
        ));
    }

    /**
     * Edita as informações do orçamento selecionado
     * 
     * @param integer $id
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
     */
    public function editAction($id, Request $request)
    {
        $budget = $this->getDoctrine()->getRepository('CDGBundle:Budget')->find($id);
        $form = $this->createForm(new BudgetType(), $budget);
        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($budget);
            $em->flush();

            return $this->redirectToRoute('budgets');
        }

        return $this->render('budget/edit.html.twig', array(
            'form' => $form->createView(),
            'title' => 'Editar orçamento #' . $budget->getId()
        ));
    }

    /**
     * Deleção de um orçamento
     * 
     * @param integer $id
     * @return Budget
     */
    public function deleteAction($id)
    {
        $budget = $this->getDoctrine()->getRepository('CDGBundle:Budget')->find($id);
        $em = $this->getDoctrine()->getManager();
        $em->remove($budget);
        $em->flush();

        return $this->redirectToRoute('budgets');
    }
}
EDIT2

我刚刚意识到@ORM\PreUpdate正在运行,但仅适用于我的
nextPaymentDate
。我在
预算
中有一个
集合
,在
产品控制器
中有一种收集产品信息的方法:

<?php

namespace CDGBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use CDGBundle\Entity\Product;
use CDGBundle\Form\ProductType;
use Symfony\Component\HttpFoundation\JsonResponse;

class ProductController extends Controller
{
    /**
     * Lista todos os materials
     */
    public function indexAction()
    {
        return $this->render('product/index.html.twig', array(
            'products' => $this->getDoctrine()->getRepository('CDGBundle:Product')->findAll(),
            'title' => 'Lista de Materiais'
        ));
    }

    /**
     * Adicionar um novo material
     * 
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
     */
    public function addAction(Request $request)
    {
        $product = new Product();
        $form = $this->createForm(new ProductType(), $product);
        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($product);
            $em->flush();

            return $this->redirectToRoute('products');
        }

        return $this->render('product/add.html.twig', array(
            'form' => $form->createView(),
            'title' => 'Novo Material'
        ));
    }

    /**
     * Exibe os detalhes do material selecionado
     * 
     * @param integer $id
     * @return Product
     */
    public function showAction($id)
    {
        $product = $this->getDoctrine()->getRepository('CDGBundle:Product')->find($id);

        return $this->render('product/show.html.twig', array(
            'product' => $product,
            'title' => 'Dados do material #' . $product->getId()
        ));
    }

    /**
     * Edita as informações do material selecionado
     * 
     * @param integer $id
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
     */
    public function editAction($id, Request $request)
    {
        $product = $this->getDoctrine()->getRepository('CDGBundle:Product')->find($id);
        $form = $this->createForm(new ProductType(), $product);
        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->merge($product);
            $em->flush();

            return $this->redirectToRoute('products');
        }

        return $this->render('product/edit.html.twig', array(
            'form' => $form->createView(),
            'title' => 'Editar material #' . $product->getId() . ' - ' . $product->getName()
        ));
    }

    /**
     * Deleção de um material
     * 
     * @param integer $id
     * @return Product
     */
    public function deleteAction($id)
    {
        $product = $this->getDoctrine()->getRepository('CDGBundle:Product')->find($id);
        $em = $this->getDoctrine()->getManager();
        $em->remove($product);
        $em->flush();

        return $this->redirectToRoute('products');
    }

    /**
     * Traz as informações do material selecionado na criação do orçamento.
     * 
     * @param Request $request
     * @return JsonResponse
     */
    public function getProductInfoAction(Request $request)
    {
        $id = $request->query->get('id');
        $product = $this->getDoctrine()->getRepository('CDGBundle:Product')->find($id);

        if ($request->query->get('format') == 'json') {
            $data = array(
                'id' => $product->getId(),
                'name' => $product->getName(),
                'price' => $product->getPrice(),
                'meters' => $product->getMeters(),
                'description' => $product->getDescription(),
                'created_at' => $product->getCreatedAt()->format('d-m-Y H:i'),
            );

            return new JsonResponse($data, 200, array(
                'Content-type' => 'application/json'
            ));
        }
    }
}
请参见,特别是预科生

应注意,此事件仅在初始启动时触发 实体的持久化(即,它不会在将来的更新中触发)

因此,您还需要添加一个预更新侦听器。

请参阅,特别是预更新侦听器

应注意,此事件仅在初始启动时触发 实体的持久化(即,它不会在将来的更新中触发)


因此,您还需要添加一个预更新侦听器。

我刚刚看到了它。更新后执行
calculateTotalPrice
方法,因为它实际上是一个设置总值的JavaScript函数。这种方法实际上是无用的。但是,添加预更新仍然不起作用。我在PrePersist下面添加了注释,或者我需要创建另一个方法?您的实体上是否设置了@ORM\HasLifecycleCallbacks?您可以在单个方法上同时设置更新/持久化,这样就不会有问题了。是的,我会这样做,因为我创建了它。我看不出您所做的有任何错误。我甚至在本地测试了一个类似的类型方法,它可以在实体的创建和更新上工作。请你看看我在Github中的项目,看看我是否做错了什么?我刚看到。更新后执行
calculateTotalPrice
方法,因为它实际上是一个设置总值的JavaScript函数。这种方法实际上是无用的。但是,添加预更新仍然不起作用。我在PrePersist下面添加了注释,或者我需要创建另一个方法?您的实体上是否设置了@ORM\HasLifecycleCallbacks?您可以在单个方法上同时设置更新/持久化,这样就不会有问题了。是的,我会这样做,因为我创建了它。我看不出您所做的有任何错误。我甚至在本地测试了一个类似的类型方法,它可以在实体的创建和更新上工作。请你看看我在Github中的项目,看看我是否做错了什么?
<?php

namespace CDGBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use CDGBundle\Entity\Product;
use CDGBundle\Form\ProductType;
use Symfony\Component\HttpFoundation\JsonResponse;

class ProductController extends Controller
{
    /**
     * Lista todos os materials
     */
    public function indexAction()
    {
        return $this->render('product/index.html.twig', array(
            'products' => $this->getDoctrine()->getRepository('CDGBundle:Product')->findAll(),
            'title' => 'Lista de Materiais'
        ));
    }

    /**
     * Adicionar um novo material
     * 
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
     */
    public function addAction(Request $request)
    {
        $product = new Product();
        $form = $this->createForm(new ProductType(), $product);
        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($product);
            $em->flush();

            return $this->redirectToRoute('products');
        }

        return $this->render('product/add.html.twig', array(
            'form' => $form->createView(),
            'title' => 'Novo Material'
        ));
    }

    /**
     * Exibe os detalhes do material selecionado
     * 
     * @param integer $id
     * @return Product
     */
    public function showAction($id)
    {
        $product = $this->getDoctrine()->getRepository('CDGBundle:Product')->find($id);

        return $this->render('product/show.html.twig', array(
            'product' => $product,
            'title' => 'Dados do material #' . $product->getId()
        ));
    }

    /**
     * Edita as informações do material selecionado
     * 
     * @param integer $id
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
     */
    public function editAction($id, Request $request)
    {
        $product = $this->getDoctrine()->getRepository('CDGBundle:Product')->find($id);
        $form = $this->createForm(new ProductType(), $product);
        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->merge($product);
            $em->flush();

            return $this->redirectToRoute('products');
        }

        return $this->render('product/edit.html.twig', array(
            'form' => $form->createView(),
            'title' => 'Editar material #' . $product->getId() . ' - ' . $product->getName()
        ));
    }

    /**
     * Deleção de um material
     * 
     * @param integer $id
     * @return Product
     */
    public function deleteAction($id)
    {
        $product = $this->getDoctrine()->getRepository('CDGBundle:Product')->find($id);
        $em = $this->getDoctrine()->getManager();
        $em->remove($product);
        $em->flush();

        return $this->redirectToRoute('products');
    }

    /**
     * Traz as informações do material selecionado na criação do orçamento.
     * 
     * @param Request $request
     * @return JsonResponse
     */
    public function getProductInfoAction(Request $request)
    {
        $id = $request->query->get('id');
        $product = $this->getDoctrine()->getRepository('CDGBundle:Product')->find($id);

        if ($request->query->get('format') == 'json') {
            $data = array(
                'id' => $product->getId(),
                'name' => $product->getName(),
                'price' => $product->getPrice(),
                'meters' => $product->getMeters(),
                'description' => $product->getDescription(),
                'created_at' => $product->getCreatedAt()->format('d-m-Y H:i'),
            );

            return new JsonResponse($data, 200, array(
                'Content-type' => 'application/json'
            ));
        }
    }
}