#symfony
#symfony
Вопрос:
Я получаю следующую ошибку:
Ожидаемое значение типа «SourcingBundle Entity RequestForEstimate» для поля ассоциации «SourcingBundle Entity RequestForEstimateDetail # $ detail» вместо этого получило «Doctrine Common Collections ArrayCollection».
Я пытаюсь создать структуру, в которой есть объект RequestForEstimate, который может иметь несколько узлов RequestForEstimateDetails. Просто каждая строка в RequestForEstimateDetails будет содержать запрос на другой продукт и его детали, когда requestforest оценивает только общую информацию. Я новичок в Symfony, и мне трудно в тот момент, когда я хочу сохранить родительский элемент вместе с дочерними элементами в БД. Я следил за этим руководством по Symfony: как внедрить коллекцию форм
Вот мой код:
SourcingBundle Entity RequestForEstimate:
<?php
namespace SourcingBundleEntity;
use DoctrineORMMapping as ORM;
/**
* RequestForEstimate
*
* @ORMTable(name="request_for_estimate")
* @ORMEntity(repositoryClass="SourcingBundleRepositoryRequestForEstimateRepository")
*/
class RequestForEstimate
{
/**
* @var int
*
* @ORMColumn(name="request_id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var int
*
* @ORMColumn(name="status", type="integer")
*/
private $status;
/**
* @var DateTime
*
* @ORMColumn(name="create_time", type="datetime")
*/
private $createTime;
/**
* @var DateTime
*
* @ORMColumn(name="update_time", type="datetime")
*/
private $updateTime;
/**
* @var string
*
* @ORMColumn(name="name", type="string", length=255)
*/
private $name;
/**
* @ORMOneToMany(targetEntity="RequestForEstimateDetail", mappedBy="detail", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private $details;
/**
* Get id
*
* @return int
*/
/**
* Constructor
*/
public function __construct()
{
$this->details = new DoctrineCommonCollectionsArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set status
*
* @param integer $status
*
* @return RequestForEstimate
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get status
*
* @return integer
*/
public function getStatus()
{
return $this->status;
}
/**
* Set createTime
*
* @param DateTime $createTime
*
* @return RequestForEstimate
*/
public function setCreateTime($createTime)
{
$this->createTime = $createTime;
return $this;
}
/**
* Get createTime
*
* @return DateTime
*/
public function getCreateTime()
{
return $this->createTime;
}
/**
* Set updateTime
*
* @param DateTime $updateTime
*
* @return RequestForEstimate
*/
public function setUpdateTime($updateTime)
{
$this->updateTime = $updateTime;
return $this;
}
/**
* Get updateTime
*
* @return DateTime
*/
public function getUpdateTime()
{
return $this->updateTime;
}
/**
* Set name
*
* @param string $name
*
* @return RequestForEstimate
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Add detail
*
* @param SourcingBundleEntityRequestForEstimateDetail $detail
*
* @return RequestForEstimate
*/
public function addDetail(SourcingBundleEntityRequestForEstimateDetail $detail)
{
$this->details[] = $detail;
return $this;
}
/**
* Remove detail
*
* @param SourcingBundleEntityRequestForEstimateDetail $detail
*/
public function removeDetail(SourcingBundleEntityRequestForEstimateDetail $detail)
{
$this->details->removeElement($detail);
}
/**
* Get details
*
* @return DoctrineCommonCollectionsCollection
*/
public function getDetails()
{
return $this->details;
}
}
SourcingBundle Entity RequestForEstimateDetail:
<?php
namespace SourcingBundleEntity;
use DoctrineORMMapping as ORM;
/**
* RequestForEstimateDetail
*
* @ORMTable(name="request_for_estimate_detail")
* @ORMEntity(repositoryClass="SourcingBundleRepositoryRequestForEstimateDetailRepository")
*/
class RequestForEstimateDetail
{
/**
* @var int
*
* @ORMColumn(name="request_detail_id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORMManyToOne(targetEntity="RequestForEstimate", inversedBy="details")
* @ORMJoinColumn(name="request_id", referencedColumnName="request_id")
*/
private $detail;
/**
* @var int
*
* @ORMColumn(name="product_id", type="integer")
*/
private $productId;
/**
* @var int
*
* @ORMColumn(name="quantity", type="integer")
*/
private $quantity;
/**
* @var string
*
* @ORMColumn(name="price_per_unit", type="decimal", precision=2, scale=0)
*/
private $pricePerUnit;
/**
* @var string
*
* @ORMColumn(name="shipping_cost", type="decimal", precision=2, scale=0)
*/
private $shippingCost;
/**
* @var string
*
* @ORMColumn(name="other_fees", type="decimal", precision=2, scale=0)
*/
private $otherFees;
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set product
*
* @param integer $product
*
* @return RequestForEstimateDetail
*/
public function setProduct($product)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* @return int
*/
public function getProduct()
{
return $this->product;
}
/**
* Set quantity
*
* @param integer $quantity
*
* @return RequestForEstimateDetail
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
return $this;
}
/**
* Get quantity
*
* @return int
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* Set pricePerUnit
*
* @param string $pricePerUnit
*
* @return RequestForEstimateDetail
*/
public function setPricePerUnit($pricePerUnit)
{
$this->pricePerUnit = $pricePerUnit;
return $this;
}
/**
* Get pricePerUnit
*
* @return string
*/
public function getPricePerUnit()
{
return $this->pricePerUnit;
}
/**
* Set shippingCost
*
* @param string $shippingCost
*
* @return RequestForEstimateDetail
*/
public function setShippingCost($shippingCost)
{
$this->shippingCost = $shippingCost;
return $this;
}
/**
* Get shippingCost
*
* @return string
*/
public function getShippingCost()
{
return $this->shippingCost;
}
/**
* Set otherFees
*
* @param string $otherFees
*
* @return RequestForEstimateDetail
*/
public function setOtherFees($otherFees)
{
$this->otherFees = $otherFees;
return $this;
}
/**
* Get otherFees
*
* @return string
*/
public function getOtherFees()
{
return $this->otherFees;
}
/**
* Set requestId
*
* @param SourcingBundleEntityRequestForEstimate $requestId
*
* @return RequestForEstimateDetail
*/
public function setRequestId(SourcingBundleEntityRequestForEstimate $requestId = null)
{
$this->requestId = $requestId;
return $this;
}
/**
* Get requestId
*
* @return SourcingBundleEntityRequestForEstimate
*/
public function getRequestId()
{
return $this->requestId;
}
/**
* Set productId
*
* @param SourcingBundleEntityProduct $productId
*
* @return RequestForEstimateDetail
*/
public function setProductId(SourcingBundleEntityProduct $productId = null)
{
$this->productId = $productId;
return $this;
}
/**
* Get productId
*
* @return SourcingBundleEntityProduct
*/
public function getProductId()
{
return $this->productId;
}
/**
* Set detail
*
* @param SourcingBundleEntityRequestForEstimate $detail
*
* @return RequestForEstimateDetail
*/
public function setDetail(SourcingBundleEntityRequestForEstimate $detail = null)
{
$this->detail = $detail;
return $this;
}
/**
* Get detail
*
* @return SourcingBundleEntityRequestForEstimate
*/
public function getDetail()
{
return $this->detail;
}
/**
* Constructor
*/
public function __construct()
{
$this->detail = new DoctrineCommonCollectionsArrayCollection();
}
/**
* Add detail
*
* @param SourcingBundleEntityRequestForEstimate $detail
*
* @return RequestForEstimateDetail
*/
public function addDetail(SourcingBundleEntityRequestForEstimate $detail)
{
$this->detail[] = $detail;
return $this;
}
/**
* Remove detail
*
* @param SourcingBundleEntityRequestForEstimate $detail
*/
public function removeDetail(SourcingBundleEntityRequestForEstimate $detail)
{
$this->detail->removeElement($detail);
}
}
Мой контроллер:
<?php
namespace SourcingBundleController;
use SourcingBundleEntityRequestForEstimate;
use SourcingBundleEntityRequestForEstimateDetail;
use SourcingBundleFormTypeRequestForEstimateType;
use SourcingBundleFormTypeRequestForEstimateDetailType;
use SymfonyBundleFrameworkBundleControllerController;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentFormExtensionCoreTypeTextType;
use SymfonyComponentFormExtensionCoreTypeDateType;
use SymfonyComponentFormExtensionCoreTypeCollectionType;
use SymfonyComponentFormExtensionCoreTypeSubmitType;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
class RequestForEstimateController extends Controller
{
/**
* @Route("sourcing/request-for-estimate", name="request_for_estimate")
*/
public function addRequest(Request $request)
{
$RequestForEstimate = new RequestForEstimate();
$form = $this->createForm(RequestForEstimateType::class, $RequestForEstimate);
$form->handleRequest($request);
if ($form->isSubmitted() amp;amp; $form->isValid()) {
$request = $form->getData();
foreach($form->get('details')->getData() as $detail)
{
$request->addDetail($detail);
}
print_r($form->get('details')->getData());
$request->setStatus(0);
$request->setupdateTime(new DateTime());
$request->setcreateTime(new DateTime());
$em = $this->getDoctrine()->getManager();
$em->persist($request);
$em->flush();
return $this->redirectToRoute('RequestsForEstimate');
}
return $this->render('sourcing/requestforestimate/create.html.twig', array(
'form' => $form->createView(),
));
}
}
Мои формы:
<?php
namespace SourcingBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
use SymfonyComponentFormExtensionCoreTypeTextareaType;
use SymfonyComponentFormExtensionCoreTypeEmailType;
use SymfonyComponentFormExtensionCoreTypeDateTimeType;
use SymfonyComponentFormExtensionCoreTypeCollectionType;
use SymfonyComponentFormExtensionCoreTypeSubmitType;
class RequestForEstimateType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('details', CollectionType::class, array(
'entry_type' => RequestForEstimateDetailType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
));
$builder->add('save', SubmitType::class, array('label' => 'Create Request'));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'SourcingBundleEntityRequestForEstimate',
));
}
}
<?php
namespace SourcingBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
class RequestForEstimateDetailType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('quantity');
$builder->add('pricePerUnit');
$builder->add('shippingCost');
$builder->add('otherFees');
// $builder->add('product');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'SourcingBundleEntityRequestForEstimateDetail',
));
}
}
Ответ №1:
В RequestForEstimateDetail
методе getter / setter поля detail предназначены для управления самой коллекцией (методы добавления / удаления предназначены для одного элемента коллекции), поэтому измените метод getter / setter для обработки ArrayCollection
объекта.
В качестве примера:
RequestForEstimateDetail
/**
* Set detail
*
* @param DoctrineCommonCollectionsArrayCollection an array of $detail
*
* @return RequestForEstimateDetail
*/
public function setDetail(DoctrineCommonCollectionsArrayCollection $detail = null)
{
$this->detail = $detail;
return $this;
}
/**
* Get detail
*
* @return DoctrineCommonCollectionsArrayCollection
*/
public function getDetail()
{
return $this->detail;
}
Надеюсь, это поможет
Комментарии:
1. Спасибо за ваш ответ, но он ничего не изменил. Все та же ошибка. Из того, что я вижу, вы только что изменили аннотацию doctrine, верно?
2. Привет, я предлагаю изменить сигнатуру методов, чтобы принять объект ArrayCollection.
3. Не могли бы вы привести пример?
Ответ №2:
Что ж, существующий метод addDetail в сущности RequestForEstimate сделал свое дело:
public function addDetail(SourcingBundleEntityRequestForEstimateDetail $detail)
{
$this->details->add($detail);
$detail->setDetail($this);
return $this;
}