Symfony2.1动态/扩展表单对附加部分无效
我确实使用了symfony2.1,并且我有一个表单,我用另一个表单扩展了这个表单,主要部分(来自第一个实体[Symfony2.1动态/扩展表单对附加部分无效,symfony,Symfony,我确实使用了symfony2.1,并且我有一个表单,我用另一个表单扩展了这个表单,主要部分(来自第一个实体[toolcography])本身正确有效,但另外一个不正确(ToolDocument)。以下是代码: 工具类别 namespace Einder\Has\ToolsBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use Symfony\Comp
toolcography
])本身正确有效,但另外一个不正确(ToolDocument
)。以下是代码:
工具类别
namespace Einder\Has\ToolsBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Einder\DoctrineBundle\Entity\ActiveInterface;
/**
* Einder\Has\ToolsBundle\Entity\ToolCategory
*
* @ORM\Table(name="tool_category")
* @ORM\Entity(repositoryClass="Einder\Has\ToolsBundle\Repository\ToolCategoryRepository")
* @ORM\HasLifecycleCallbacks
*/
class ToolCategory implements ActiveInterface
{
/**
* @var integer $id
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string $name
*
* @ORM\Column(name="name", type="string", length=255)
* @Assert\NotBlank()
*/
private $name;
/**
* @var text $target
*
* @ORM\Column(name="target", type="text")
* @Assert\NotBlank()
*/
private $target;
/**
* @var text $activity
*
* @ORM\Column(name="activity", type="text")
* @Assert\NotBlank()
*/
private $activity;
/**
* @var boolean $active
*
* @ORM\Column(name="active", type="boolean", nullable=true)
*/
private $active = true;
/**
* @ORM\OneToMany(targetEntity="ToolDocument", mappedBy="toolCategory", cascade={"persist", "remove"})
*/
private $documents;
/**
* @var boolean $createAnother
*
* @Assert\Type(type="boolean")
*/
private $createAnother = false;
/**
* @var datetime $createdAt
*
* @ORM\Column(name="created_at", type="datetime")
*/
private $createdAt;
/**
* @var datetime $updatedAt
*
* @ORM\Column(name="updated_at", type="datetime")
*/
private $updatedAt;
/**
* Constructor
*/
public function __construct()
{
$this->documents = new ArrayCollection();
}
/**
* __toString
*/
public function __toString()
{
return $this->name;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set target
*
* @param text $target
*/
public function setTarget($target)
{
$this->target = $target;
}
/**
* Get target
*
* @return text
*/
public function getTarget()
{
return $this->target;
}
/**
* Set activity
*
* @param text $activity
*/
public function setActivity($activity)
{
$this->activity = $activity;
}
/**
* Get activity
*
* @return text
*/
public function getActivity()
{
return $this->activity;
}
/**
* Set active
*
* @param boolean $active
*/
public function setActive($active = true)
{
$this->active = $active;
}
/**
* Get active
*
* @return boolean
*/
public function getActive()
{
return $this->active;
}
/**
* Add documents
*
* @param Einder\Has\ToolsBundle\Entity\ToolDocument $documents
*/
public function addToolDocument(\Einder\Has\ToolsBundle\Entity\ToolDocument $documents)
{
$this->documents[] = $documents;
}
/**
* Get documents
*
* @return Doctrine\Common\Collections\Collection
*/
public function getDocuments()
{
return $this->documents;
}
/**
* Set createAnother
*
* @param boolean $createAnother
*/
public function setCreateAnother($createAnother)
{
$this->createAnother = $createAnother;
}
/**
* Get createAnother
*
* @return boolean
*/
public function getCreateAnother()
{
return $this->createAnother;
}
/**
* Set createdAt
*
* @ORM\PrePersist
*/
public function setCreatedAt()
{
$this->createdAt = new \DateTime();
}
/**
* Get createdAt
*
* @return datetime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set updatedAt
*
* @ORM\PrePersist
* @ORM\PreUpdate
*/
public function setUpdatedAt()
{
$this->updatedAt = new \DateTime();
}
/**
* Get updatedAt
*
* @return datetime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
public function setDocuments($documents) {
$this->documents = $documents;
foreach ($documents as $document) {
$document->setToolCategory($this);
}
}
}
工具文档
namespace Einder\Has\ToolsBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Einder\DoctrineBundle\Entity\EntityInterface;
/**
* Einder\Has\ToolsBundle\Entity\ToolDocument
*
* @ORM\Table(name="tool_document")
* @ORM\Entity(repositoryClass="Einder\Has\ToolsBundle\Repository\ToolDocumentRepository")
* @ORM\HasLifecycleCallbacks
*/
class ToolDocument implements EntityInterface
{
/**
* @var integer $id
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @Assert\File(maxSize="6000000")
*/
public $file;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank()
* @Assert\NotNull()
* @Assert\MinLength(10)
*/
private $name;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $path;
/**
* @var boolean $active
*
* @ORM\Column(name="active", type="boolean", nullable=true)
*/
private $active = true;
/**
* @var boolean $deleted
*
* @ORM\Column(name="deleted", type="boolean", nullable=true)
*/
private $deleted = false;
/**
* @var datetime $deletedAt
*
* @ORM\Column(name="deleted_at", type="boolean", nullable=true)
*/
private $deletedAt;
/**
* @ORM\ManyToOne(targetEntity="ToolCategory", inversedBy="documents")
* @ORM\JoinColumn(name="tool_category_id", referencedColumnName="id")
*/
private $toolCategory;
/**
* @var datetime $createdAt
*
* @ORM\Column(name="created_at", type="datetime")
*/
private $createdAt;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
public function __toString()
{
return $this->name;
}
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path ? null : $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded documents should be saved
return __DIR__.'/../../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
return '/uploads/tools';
}
/**
* @ORM\PrePersist()
* @ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file) {
// do whatever you want to generate a unique name
$this->setPath(uniqid() . '.' . pathinfo($this->file->getClientOriginalName(), PATHINFO_EXTENSION));
}
}
/**
* @ORM\PostPersist()
* @ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
// you must throw an exception here if the file cannot be moved
// so that the entity is not persisted to the database
// which the UploadedFile move() method does automatically
$this->file->move($this->getUploadRootDir(), $this->path);
unset($this->file);
}
/**
* @ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
/**
* Set name
*
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set path
*
* @param string $path
*/
public function setPath($path)
{
$this->path = $path;
}
/**
* Get path
*
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* Set active
*
* @param boolean $active
*/
public function setActive($active = true)
{
$this->active = $active;
}
/**
* Get active
*
* @return boolean
*/
public function getActive()
{
return $this->active;
}
/**
* Set deleted
*
* @param boolean $deleted
*/
public function setDeleted($deleted = false)
{
$this->deleted = $deleted;
}
/**
* Get deleted
*
* @return boolean
*/
public function getDeleted()
{
return $this->deleted;
}
/**
* Get deletedAt
*
* @return datetime
*/
public function getDeletedAt()
{
return $this->deletedAt;
}
/**
* Set deletedAt
*
* @param boolean $deletedAt
*/
public function setDeletedAt(\DateTime $deletedAt = null)
{
$this->deletedAt = $deletedAt;
}
/**
* Set toolCategory
*
* @param Einder\Has\ToolsBundle\Entity\ToolCategory $toolCategory
*/
public function setToolCategory($toolCategory)
{
$this->toolCategory = $toolCategory;
}
/**
* Get toolCategory
*
* @return Einder\Has\ToolsBundle\Entity\ToolCategory
*/
public function getToolCategory()
{
return $this->toolCategory;
}
/**
* Set createdAt
*
* @ORM\PrePersist
*/
public function setCreatedAt()
{
$this->createdAt = new \DateTime();
}
/**
* Get createdAt
*
* @return datetime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set updatedAt
*
* @ORM\PrePersist
* @ORM\PreUpdate
*/
public function setUpdatedAt()
{
$this->updatedAt = new \DateTime();
}
/**
* Get updatedAt
*
* @return datetime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
}
工具类别类型
namespace Einder\Has\ToolsBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Einder\Has\ToolsBundle\Form\Type\ToolDocumentType;
class ToolCategoryType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('name', null, array('label' => 'tool.category.form.labels.name'))
->add('target', null, array('label' => 'tool.category.form.labels.target'))
->add('activity', null, array('label' => 'tool.category.form.labels.activity'))
->add('createAnother', null, array('label' => 'tool.category.form.labels.create_another'))
->add('documents', 'collection', array(
'by_reference' => false,
'type' => new ToolDocumentType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'error_bubbling' => true
));
}
public function getDefaultOptions()
{
return array(
'data_class' => 'Einder\Has\ToolsBundle\Entity\ToolCategory'
);
}
public function getName()
{
return 'tool_category';
}
}
工具文档类型
namespace Einder\Has\ToolsBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ToolDocumentType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name', null, array('label' => 'tool.document.form.labels.name'))
->add('file', null, array('label' => 'tool.document.form.labels.file'));
}
public function getDefaultOptions()
{
return array(
'data_class' => 'Einder\Has\ToolsBundle\Entity\ToolDocument',
'cascade_validation' => true,
);
}
public function getName()
{
return 'tool_document';
}
}
{{form_errors(form)}
{{form_标签(form.name)}
{{form_小部件(form.name)}{{form_错误(form.name)}}
{{form_标签(form.target)}
{{form_小部件(form.target)}{{form_错误(form.target)}}
{{form_标签(form.activity)}
{{form_小部件(form.activity)}{{form_错误(form.activity)}}
{{form_标签(form.documents)}
{form.documents%中的行的%s}
{{{u self.widget{u原型(行)}
{%endfor%}
{{form_rest(form)}
{%block javascripts%}
函数add(){
var collectionHolder=$(“#工具#类别#文档”);
var-prototype=collectionHolder.attr('data-prototype');
控制台日志(collectionHolder);
form=prototype.replace(/uuu name_uuu/g,$(“#小部件集合持有者”).children().length);
console.log($(表单));
collectionHolder.find(“#widget collection holder”).append(表单);
}
函数移除(对象){
$(对象).parent().remove();
}
$('a.jslink_add').live('click',函数(事件){
event.preventDefault();
添加();
});
$('a.jslink_remove').live('click',函数(事件){
event.preventDefault();
移除(此);
});
{%endblock%}
{%macro小部件\原型(小部件)%}
{%if widget.get('prototype')%}
{%set form=widget.get('prototype')%}
{%set name=widget.get('prototype').get('name')%}
{%else%}
{%set form=widget%}
{%set name=widget.get('full_name')%}
{%endif%}
{{form_errors(form)}{{form_widget(form.name)}}{{form_widget(form.file)}}
{%endmacro%}
谢谢你的回答 你应该
- 将
约束放在@Assert\Valid
(首选解决方案)上,或工具类别::$documents
- 在父窗体(即
)上,而不是在子窗体上,将ToolCategoryType
cascade\u验证设置为
true
{{ form_errors(form) }}
<form method="post" {{ form_enctype(form) }} novalidate>
<table class="table table-striped">
<tbody>
<tr>
<td>{{ form_label(form.name) }}</td>
<td>{{ form_widget(form.name) }} {{ form_errors(form.name) }}</td>
</tr>
<tr>
<td>{{ form_label(form.target) }}</td>
<td>{{ form_widget(form.target) }} {{ form_errors(form.target) }}</td>
</tr>
<tr>
<td>{{ form_label(form.activity) }}</td>
<td>{{ form_widget(form.activity) }} {{ form_errors(form.activity) }}</td>
</tr>
<tr id="tool_category_documents" data-prototype="{{ _self.widget_prototype(form.documents, 'Remove tag')|escape }}">
<td>{{ form_label(form.documents) }}</td>
<td id="widget-collection-holder">
{% for row in form.documents %}
{{ _self.widget_prototype(row) }}
{% endfor %}
</td>
</tr>
<tr>
<td><a class="jslink_add">{{ 'Add'|trans }}</a></td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td>{{ form_label(form.createAnother) }} {{ form_widget(form.createAnother) }} {{ form_errors(form.createAnother) }}</td>
<td>
<input type="submit" value="{{ 'admin.tools.categories.category.form.save'|trans }}" class="btn btn-success" />
<a href="{{ path('admin_tools_index')}}" class="btn btn-danger">{{ 'global.action.cancel'}}</a>
</td>
</tr>
<tr>
<td>{{ form_rest(form) }}</td>
<td></td>
</tr>
</tfoot>
</table>
</form>
{% block javascripts %}
<script type="text/javascript">
function add() {
var collectionHolder = $('#tool_category_documents');
var prototype = collectionHolder.attr('data-prototype');
console.log(collectionHolder);
form = prototype.replace(/__name__/g, $('#widget-collection-holder').children().length);
console.log($(form));
collectionHolder.find('#widget-collection-holder').append(form);
}
function remove(object) {
$(object).parent().remove();
}
$('a.jslink_add').live('click', function(event){
event.preventDefault();
add();
});
$('a.jslink_remove').live('click', function(event){
event.preventDefault();
remove(this);
});
</script>
{% endblock %}
{% macro widget_prototype(widget) %}
{% if widget.get('prototype') %}
{% set form = widget.get('prototype') %}
{% set name = widget.get('prototype').get('name') %}
{% else %}
{% set form = widget %}
{% set name = widget.get('full_name') %}
{% endif %}
<div class="widget-holder">{{ form_errors(form) }} {{ form_widget(form.name) }} {{ form_widget(form.file)}} <a href="#" class="jslink_remove">{{ 'Remove'|trans }}</a></div>
{% endmacro %}