我遇到需要更新Doctrine2实体并排除某些字段的情况。
使用ZF2,我有一个动作来使用Zend \ Form和验证过滤器来处理更新。特别是Dish
实体有一个名为photo
的blob列,必需。在更新期间,我只想在提供新文件时替换照片。
这里有实体的源代码和更新盘子的控制器动作。
餐具\实体\ Dish.php
<?php
namespace Dishes\Entity;
use Doctrine\ORM\Mapping as ORM;
/** @ORM\Entity **/
class Dish
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
**/
protected $id;
/**
* @ORM\Column(type="string")
*/
protected $name;
/**
* @ORM\Column(type="text")
*/
protected $description;
/**
* @ORM\Column(type="integer")
*/
protected $time;
/**
* @ORM\Column(type="integer")
*/
protected $complexity;
/**
* @ORM\Column(type="blob")
*/
protected $photo;
/**
* Magic getter to expose protected properties.
*
* @param string $property
* @return mixed
*/
public function __get($property)
{
return $this->$property;
}
/**
* Magic setter to save protected properties.
*
* @param string $property
* @param mixed $value
*/
public function __set($property, $value)
{
$this->$property = $value;
}
}
餐具\控制器\ AdminController.php
public function editDishAction()
{
//Params from url
$id = (int) $this->params()->fromRoute('id', 0);
$objectManager = $this->objectManager;
$hydrator = new DoctrineObject($objectManager, false);
$form = new DishForm();
$existingDish = $objectManager->find('Dishes\Entity\Dish', $id);
if ($existingDish === NULL)
$this->notFoundAction();
$request = $this->getRequest();
if ($request->isPost())
{
$filter = new DishFilter();
$filter->get('photo')->setRequired(false);
$form->setHydrator($hydrator)
->setObject($existingDish)
->setInputFilter($filter);
$post = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
//Backup photo stream
$imageData = $existingDish->photo;
$form->setData($post);
if ($form->isValid())
{
//If user upload a new image read it.
if(!empty($existingDish->photo['tmp_name']))
$imageData = file_get_contents($existingDish->photo['tmp_name']);
$existingDish->photo = $imageData;
$objectManager->flush();
$this->redirect()->toRoute('zfcadmin/dishes');
}
}
else
{
$data = $hydrator->extract($existingDish);
unset($data['photo']);
$form->setData($data);
}
return new ViewModel(array('form' => $form));
}
实际上我将$dish->photo
属性设置为NULL
,但这违反了 DB NOT NULL 约束。
如何告诉Doctrine在运行时从更新中排除特定的实体字段?
答案 0 :(得分:0)
默认情况下,Doctrine将数据库级别中每列的nullable
属性映射到false
,因为您没有在注释中设置任何nullable
标记:
/**
* @ORM\Column(type="blob")
*/
protected $photo;
这意味着,“照片是必需的,您无法使用空值插入或更新行的照片列。”
如果要在数据库中包含null
值,请使用以下注释:
/**
* @ORM\Column(type="blob", nullable=true)
*/
protected $photo;
并且在它的setter中不要忘记null
默认参数值:
public function setPhoto($photo = null)
{
$this->photo = $photo;
}
对于这个问题;看起来你正在为动作中的每个编辑操作设置一个新的Dish对象:
$form->setHydrator($hydrator)
->setObject(new Dish)
->setInputFilter($filter);
创建新Dish对象时这是正确的。编辑时,您必须将已保留的Dish实例设置为以下格式:
// I'm just writing to explain the flow.
// Accessing the object repository in action level is not a good practice.
// Use a DishService for example.
$id = 32; // Grab it from route or elsewhere
$repo = $entityManager->getRepository('Dishes\Entity\Dish');
$existingDish = $repo->findOne((int) $id);
$form->setHydrator($hydrator)
->setObject($existingDish)
->setInputFilter($filter);
我假设这是现有Dish的编辑操作。
因此,水合器将在下次调用时正确处理已更改和未触摸的字段,因为您通过表单提供已填充的Dish实例。
我还建议从DishFilter
中提取InputFilterManager
,而不是在操作级别手动创建它:
// $filter = new DishFilter();
$filter = $serviceLocator->get('InputFilterManager')->get(DishFilter::class);
// Exclude the photo on validation:
$filter->setValidationGroup('name', 'description', 'time', 'complexity');
希望它有所帮助。