对于我的项目中的类别结构,我正在构建一个实体。对于添加表单,我使用DoctrineObject水合器。当$ parent的值存在时,这可以正常工作,但是如果没有父项,它会给我一个错误,因为没有id可以选择父项。在这种情况下,parent属性的值应为null。
我会创建一个过滤器来执行此操作。执行此过滤器但是水合器似乎没有达到我想要的效果。
有人知道如何解决这个问题吗?
我的实体:
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;
答案 0 :(得分:0)
我通过创建一个基于“DoctrineModule \ Form \ ElementObjectSelect”的“HiddenElement”元素来解决这个问题,并将其用作输入类型。
答案 1 :(得分:0)
您需要一个处理''值的策略。 (''!= null)因为ocramius指出它可能有''。
的主键你使用“empty_option”时遇到了这个问题,目前你只能将null设置为null,表单帖子将始终转移''。
请参阅https://github.com/doctrine/DoctrineModule/pull/119
请参阅https://github.com/doctrine/DoctrineModule/pull/106
所以将此字段的策略添加到水化器中以将''转换为null。
这可能看起来像:
use Zend\Stdlib\Hydrator\Strategy\DefaultStrategy;
class ForeignKey extends DefaultStrategy
{
public function hydrate($value)
{
if($value == '') {
return NULL;
}
return $value;
}
}