Doctrine orm ZF2和x2B;Doctrine2+;DoctrineObject对象:多通关系的空值
对于项目上的类别结构,我正在构建一个实体。对于add表单,我使用DoctrineObject或。当$parent有一个值时,这可以正常工作,但是当没有父项时,它会给我一个错误,因为没有id来选择父项。在这种情况下,父属性的值应为null 我会创建一个过滤器来实现这一点。此过滤器已执行,但水合器似乎没有得到我希望它执行的操作 有人知道怎么解决这个问题吗 我的实体:Doctrine orm ZF2和x2B;Doctrine2+;DoctrineObject对象:多通关系的空值,doctrine-orm,zend-framework2,zend-form,Doctrine Orm,Zend Framework2,Zend Form,对于项目上的类别结构,我正在构建一个实体。对于add表单,我使用DoctrineObject或。当$parent有一个值时,这可以正常工作,但是当没有父项时,它会给我一个错误,因为没有id来选择父项。在这种情况下,父属性的值应为null 我会创建一个过滤器来实现这一点。此过滤器已执行,但水合器似乎没有得到我希望它执行的操作 有人知道怎么解决这个问题吗 我的实体: use Gedmo\Mapping\Annotation as Gedmo; use Doctrine\ORM\Mapping as
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Flex\Entity\Entity;
/**
* @Gedmo\Tree(type="materializedPath")
* @ORM\Table(name="categories")
* @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\MaterializedPathRepository")
*/
class Category extends Entity
{
/**
* @ORM\OneToMany(mappedBy="parent", targetEntity="FlexCategories\Entity\Category")
*/
protected $children;
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
protected $id;
/**
* @Gedmo\TreeLevel
* @ORM\Column(nullable=true, type="integer")
*/
protected $level;
/**
* @ORM\Column(length=64, type="string")
*/
protected $name;
/**
* @Gedmo\TreeParent
* @ORM\ManyToOne(inversedBy="children", targetEntity="FlexCategories\Entity\Category")
* @ORM\JoinColumns({
* @ORM\JoinColumn(onDelete="SET NULL", referencedColumnName="id")
* })
*/
protected $parent;
/**
* @Gedmo\TreePath(appendId=false, endsWithSeparator=false, separator="/", startsWithSeparator=true)
* @ORM\Column(length=255, nullable=true, type="string", unique=true)
*/
protected $path;
/**
* @Gedmo\Slug(fields={"name"}, unique=false)
* @Gedmo\TreePathSource
* @ORM\Column(length=64)
*/
protected $slug;
public function setId($value)
{
$this->id = $value;
}
public function setName($value)
{
$this->name = $value;
}
public function setParent($value)
{
$this->parent = $value;
}
}
我的表格:
use DoctrineModule\Stdlib\Hydrator\DoctrineObject;
use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
class CategoryForm extends Form implements InputFilterProviderInterface, ServiceManagerAwareInterface
{
private $_serviceManager;
public function init()
{
// Init hydrator
$hydrator = new DoctrineObject($this->_serviceManager->get('doctrine.entitymanager.orm_default'),
'FlexCategories\Entity\Category');
// Set form basic configurations
$this->setAttribute('method', 'post')
->setHydrator($hydrator);
// Add parent field
$this->add(array(
'name' => 'parent',
'type' => 'Zend\Form\Element\Hidden',
));
// Add name field
$this->add(array(
'attributes' => array(
'required' => 'required',
),
'name' => 'name',
'options' => array(
'label' => 'Name',
),
'type' => 'Zend\Form\Element\Text',
));
// Add description field
$this->add(array(
'name' => 'description',
'options' => array(
'label' => 'Description',
),
'type' => 'Zend\Form\Element\Textarea',
));
// Add CSRF element
$this->add(array(
'name' => 'csrf',
'type' => 'Zend\Form\Element\Csrf',
));
// Add submit button
$this->add(array(
'attributes' => array(
'type' => 'submit',
'value' => 'Save',
),
'name' => 'submit',
));
}
public function getInputFilterSpecification()
{
return array(
'description' => array(
'filters' => array(
array(
'name' => 'Zend\Filter\StringTrim'
),
),
'required' => false,
),
'name' => array(
'filters' => array(
array(
'name' => 'Zend\Filter\StringTrim'
),
),
'required' => true,
'validators' => array(
array(
'name' => 'Flex\Validator\EntityUnique',
'options' => array(
'entity' => 'FlexCategories\Entity\Category',
'filter' => array(
array('property' => 'parent',
'value' => array('_context', 'parent')),
),
'property' => 'name',
'serviceLocator' => $this->_serviceManager,
),
),
),
),
'parent' => array(
'filters' => array(
array(
'name' => 'Flex\Filter\NullIfEmpty'
),
),
'required' => false,
),
);
}
public function setServiceManager(ServiceManager $serviceManager)
{
$this->_serviceManager = $serviceManager;
$this->init();
return $this;
}
}
我的控制器:
use Flex\Controller\AbstractController;
use FlexCategories\Entity\Category;
use FlexCategories\Form\CategoryForm;
class AdminController extends AbstractController
{
public function addAction()
{
// Load form
$form = $this->getServiceLocator()->get('FlexCategories\Form\CategoryForm');
// Create and bind new entity
$category = new Category();
$form->bind($category);
// Load parent category if present
$parentId = $this->params()->fromRoute('id', null);
if ($parentId !== null)
{
if (!is_numeric($parentId))
throw new \InvalidArgumentException('Invalid parent id specified');
$entityManager = $this->getEntityManager();
$repository = $entityManager->getRepository('FlexCategories\Entity\Category');
$parent = $repository->find($parentId);
if (!$parent)
throw new \InvalidArgumentException('Invalid parent id specified');
$form->get('parent')->setValue($parent->getId());
}
// Process request
$request = $this->getRequest();
if ($request->isPost())
{
$form->setData($request->getPost());
if ($form->isValid())
{
$entityManager = $this->getEntityManager();
$entityManager->persist($category);
$entityManager->flush();
$this->flashMessenger()->addSuccessMessage(sprintf('The category "%1$s" has succesfully been added.', $category->getName()));
return $this->redirect()->toRoute($this->getEvent()->getRouteMatch()->getMatchedRouteName());
}
}
// Return form
return array(
'form' => $form,
);
}
public function indexAction()
{
// Load all categories
$entityManager = $this->getEntityManager();
$repository = $entityManager->getRepository('FlexCategories\Entity\Category');
$categories = $repository->findBy(array(), array('path' => 'asc'));
return array(
'categories' => $categories,
);
}
}
我的数据库:
CREATE TABLE `categories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`level` int(11) DEFAULT NULL,
`name` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`path` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`slug` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UNIQ_3AF34668B548B0F` (`path`),
KEY `IDX_3AF34668727ACA70` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `categories`
ADD CONSTRAINT `FK_3AF34668727ACA70` FOREIGN KEY (`parent_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL;
我可以通过基于“doctrinmodule\Form\ElementObjectSelect”创建一个“HiddenElement”元素并将其用作输入类型来解决此问题。您需要一个处理“”值的策略。(“”!=null)正如ocramius指出的那样,它可能包含带有“”的主键 您在使用“empty_option”(当前不能将其设置为null)时遇到此问题,表单post将始终传输“” 看 看 因此,请为该字段添加一个策略,或将“”转换为null 这可能看起来像:
use Zend\Stdlib\Hydrator\Strategy\DefaultStrategy;
class ForeignKey extends DefaultStrategy
{
public function hydrate($value)
{
if($value == '') {
return NULL;
}
return $value;
}
}
您需要更改您的表架构,以便在
parent\u id
列中允许null
值。实际上,我通过添加nullable=thue尝试了这一点,但这并没有什么区别。我应该怎么做?假设您使用的是MySql,并且您的parent\u id
列的类型为int(11)
sql将是ALTER TABLE categories MODIFY parent\u id int(11)默认为空代码>数据库可以将null作为值处理。当我不使用hydrator时,它工作得很好,所以我认为问题在于hydrator或hydrator.Odd的配置,因为我经常使用Gedmo\Tree扩展,唯一一次遇到这个问题是当我忘记在数据库中使列本身为空时。