多文件上传约束
Multiple file upload constraint
我按照教程管理多个文件的上传http://growingcookies.com/easy-multiple-file-upload-in-symfony-using-the-collectiontype-field/
上传多个文件的系统工作正常。
但是,我想添加一个限制条件以仅允许某些类型的文件并设置最大大小。
为此,我添加 @Assert\File
:
/**
* @Assert\File(
* maxSize = "300k",
* mimeTypes = {"application/pdf", "application/x-pdf", "text/plain", "application/msword",
* "application/vnd.ms-excel", "image/jpeg", "image/x-citrix-jpeg", "image/png", "image/x-citrix-png", "image/x-png", "image/gif",
* "application/zip"},
* mimeTypesMessage = "Liste des formats de fichiers acceptés : PDF, TXT, DOC, XLS, JPG, PNG, GIF"
* )
*
* @ORM\OneToMany(targetEntity="Maps_red\TicketingBundle\Entity\TicketDocument", mappedBy="ticket", cascade={"persist"}, orphanRemoval=true)
*/
protected $documents;
通过添加,代码不再有效。我收到以下错误:
Impossible to access an attribute ("name") on a null variable.
当我发送表单时,这个错误出现在“添加文件”页面上。错误对应的行是:
<div class="col col-xs-11" id="jsPreview{{ pos }}">{{ doc.vars.value.name }}</div>
违反约束的消息是:"The file could not be found."
你知道我的错误在哪里吗?
为@Denis Alimov 编辑:
我用 @Assert\All
尝试了 Denis Alimov 的答案,但 return 出现了同样的错误。
然后我尝试将约束放在 BuildForm 中。现在,.txt 文件顺利通过,但所有其他扩展名总是 return 我同样的错误
Impossible to access an attribute ("name") on a null variable.
为@Jakumi 编辑:
我的树枝:
{% extends '@Ticketing/base.html.twig' %}
{% block title %}{{ 'New Ticket'|trans({}, 'TicketingBundle') }}{% endblock %}
{% block header %}<h1>{{ 'New Ticket'|trans({}, 'TicketingBundle') }}</h1>{% endblock %}
{% block form_group_class -%}
col-sm-8
{%- endblock form_group_class %}
{% block main %}
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
{% form_theme form 'bootstrap_4_layout.html.twig' _self %}
<div class="box box-danger">
<div class="box-header with-border">
<h3 class="box-title">{{ 'Create a new ticket'|trans({}, 'TicketingBundle') }}</h3>
</div>
{% form_theme form 'bootstrap_3_horizontal_layout.html.twig' _self %}
{{ form_start(form, {'attr': {'class': 'form-horizontal'} }) }}
<div class="box-body">
<div class="hr-line-dashed"></div>
<div id="filesProto" data-prototype="{{ form_widget(form.documents.vars.prototype)|e }}"></div>
<div class="form-group">
<label class="col-sm-2 control-label" for="ticket_form_documents">Pièce-jointe</label>
<div class="col-sm-8" id="filesBox">
{% set pos = 0 %}
{% for doc in form.documents %}
<div class="row">
<div class="col col-xs-1" id="jsRemove{{ pos }}" style="">
<button type="button" class="btn btn-danger" onclick="removeFile($(this));"><i class="fa fa-times" aria-hidden="true"></i></button>
</div>
<div class="col col-xs-11" id="jsPreview{{ pos }}">{{ doc.vars.value.name }}</div>
<div style="display:none">
{{ form_widget(doc) }}
</div>
</div>
{% set pos = pos + 1 %}
{% endfor %}
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<div class="col-md-offset-2 col-sm-8">
<button id="dropbutton" class="btn bg-ticketing btn-flat form-control" type="submit">
{{ 'Submit the ticket'|trans({}, 'TicketingBundle') }}
</button>
</div>
</div>
<!-- /.box-footer -->
{{ form_end(form) }}
</div>
<script>
var fileCount = '{{ form.documents|length }}';
var removeButton = "<button type='button' class='btn btn-danger btn-xs' onclick='removeFile($(this));'><i class='fa fa-times' aria-hidden='true'></i></button>";
function removeFile(ob)
{
ob.parent().parent().remove();
}
function createAddFile(fileCount)
{
// grab the prototype template
var newWidget = $("#filesProto").attr('data-prototype');
// replace the "__name__" used in the id and name of the prototype
newWidget = newWidget.replace(/__name__/g, fileCount);
newWidget = "<div style='display:none'>" + newWidget + "</div>";
hideStuff = "";
hideStuff += "<div class='col col-xs-1' id='jsRemove" + fileCount + "' style='display: none;'>";
hideStuff += removeButton;
hideStuff += "</div>";
hideStuff += "<div class='col col-xs-11' id='jsPreview" + fileCount + "'>";
hideStuff += "</div>";
hideStuff += "<div class='col-sm-8'>";
hideStuff += "<button type='button' id='jsBtnUpload" + fileCount + "' class='btn btn-default'>";
hideStuff += "<i class='fa fa-plus'></i> {{ 'Pièce-jointe' | trans }}";
hideStuff += "</button>";
hideStuff += "</div>";
$("#filesBox").append("<div class='form-group'>" + hideStuff + newWidget + "</div>");
// On click => Simulate file behaviour
$("#jsBtnUpload" + fileCount).on('click', function(e){
$('#ticket_form_documents_' + fileCount + '_file').trigger('click');
});
// Once the file is added
$('#ticket_form_documents_' + fileCount + '_file').on('change', function() {
// Show its name
fileName = $(this).prop('files')[0].name;
$("#jsPreview" + fileCount).append(fileName);
// Hide the add file button
$("#jsBtnUpload" + fileCount).hide();
// Show the remove file button
$("#jsRemove" + fileCount).show();
// Create another instance of add file button and company
createAddFile(parseInt(fileCount)+1);
});
}
$(document).ready(function(){
createAddFile(fileCount);
fileCount++;
});
</script>
{% endblock %}
编辑:
与{{ doc.vars.value.name ?? '' }} 我没有错误了!!
但是,文件删除按钮仍然显示:
<div class="col col-xs-1" id="jsRemove1" style="">
<button type="button" class="btn btn-danger" onclick="removeFile($(this));"><i class="fa fa-times" aria-hidden="true"></i></button>
</div>
当文件类型不好时,如何让这些按钮消失?
正如已经提到的那样使用 All constraint
/**
* @Assert\All({
* @Assert\File(
* maxSize = "300k",
* mimeTypes = {"application/pdf", "application/x-pdf", "text/plain", "application/msword", "application/vnd.ms-excel", "image/jpeg", "image/x-citrix-jpeg", "image/png", "image/x-citrix-png", "image/x-png", "image/gif","application/zip"},
* mimeTypesMessage = "Liste des formats de fichiers acceptés : PDF, TXT, DOC, XLS, JPG, PNG, GIF"
* )
* })
*/
private $documents;
您还可以在 buildForm 方法中为您的 DocumentType 添加约束条件
我按照教程管理多个文件的上传http://growingcookies.com/easy-multiple-file-upload-in-symfony-using-the-collectiontype-field/
上传多个文件的系统工作正常。
但是,我想添加一个限制条件以仅允许某些类型的文件并设置最大大小。
为此,我添加 @Assert\File
:
/**
* @Assert\File(
* maxSize = "300k",
* mimeTypes = {"application/pdf", "application/x-pdf", "text/plain", "application/msword",
* "application/vnd.ms-excel", "image/jpeg", "image/x-citrix-jpeg", "image/png", "image/x-citrix-png", "image/x-png", "image/gif",
* "application/zip"},
* mimeTypesMessage = "Liste des formats de fichiers acceptés : PDF, TXT, DOC, XLS, JPG, PNG, GIF"
* )
*
* @ORM\OneToMany(targetEntity="Maps_red\TicketingBundle\Entity\TicketDocument", mappedBy="ticket", cascade={"persist"}, orphanRemoval=true)
*/
protected $documents;
通过添加,代码不再有效。我收到以下错误:
Impossible to access an attribute ("name") on a null variable.
当我发送表单时,这个错误出现在“添加文件”页面上。错误对应的行是:
<div class="col col-xs-11" id="jsPreview{{ pos }}">{{ doc.vars.value.name }}</div>
违反约束的消息是:"The file could not be found."
你知道我的错误在哪里吗?
为@Denis Alimov 编辑:
我用 @Assert\All
尝试了 Denis Alimov 的答案,但 return 出现了同样的错误。
然后我尝试将约束放在 BuildForm 中。现在,.txt 文件顺利通过,但所有其他扩展名总是 return 我同样的错误
Impossible to access an attribute ("name") on a null variable.
为@Jakumi 编辑:
我的树枝:
{% extends '@Ticketing/base.html.twig' %}
{% block title %}{{ 'New Ticket'|trans({}, 'TicketingBundle') }}{% endblock %}
{% block header %}<h1>{{ 'New Ticket'|trans({}, 'TicketingBundle') }}</h1>{% endblock %}
{% block form_group_class -%}
col-sm-8
{%- endblock form_group_class %}
{% block main %}
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
{% form_theme form 'bootstrap_4_layout.html.twig' _self %}
<div class="box box-danger">
<div class="box-header with-border">
<h3 class="box-title">{{ 'Create a new ticket'|trans({}, 'TicketingBundle') }}</h3>
</div>
{% form_theme form 'bootstrap_3_horizontal_layout.html.twig' _self %}
{{ form_start(form, {'attr': {'class': 'form-horizontal'} }) }}
<div class="box-body">
<div class="hr-line-dashed"></div>
<div id="filesProto" data-prototype="{{ form_widget(form.documents.vars.prototype)|e }}"></div>
<div class="form-group">
<label class="col-sm-2 control-label" for="ticket_form_documents">Pièce-jointe</label>
<div class="col-sm-8" id="filesBox">
{% set pos = 0 %}
{% for doc in form.documents %}
<div class="row">
<div class="col col-xs-1" id="jsRemove{{ pos }}" style="">
<button type="button" class="btn btn-danger" onclick="removeFile($(this));"><i class="fa fa-times" aria-hidden="true"></i></button>
</div>
<div class="col col-xs-11" id="jsPreview{{ pos }}">{{ doc.vars.value.name }}</div>
<div style="display:none">
{{ form_widget(doc) }}
</div>
</div>
{% set pos = pos + 1 %}
{% endfor %}
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<div class="col-md-offset-2 col-sm-8">
<button id="dropbutton" class="btn bg-ticketing btn-flat form-control" type="submit">
{{ 'Submit the ticket'|trans({}, 'TicketingBundle') }}
</button>
</div>
</div>
<!-- /.box-footer -->
{{ form_end(form) }}
</div>
<script>
var fileCount = '{{ form.documents|length }}';
var removeButton = "<button type='button' class='btn btn-danger btn-xs' onclick='removeFile($(this));'><i class='fa fa-times' aria-hidden='true'></i></button>";
function removeFile(ob)
{
ob.parent().parent().remove();
}
function createAddFile(fileCount)
{
// grab the prototype template
var newWidget = $("#filesProto").attr('data-prototype');
// replace the "__name__" used in the id and name of the prototype
newWidget = newWidget.replace(/__name__/g, fileCount);
newWidget = "<div style='display:none'>" + newWidget + "</div>";
hideStuff = "";
hideStuff += "<div class='col col-xs-1' id='jsRemove" + fileCount + "' style='display: none;'>";
hideStuff += removeButton;
hideStuff += "</div>";
hideStuff += "<div class='col col-xs-11' id='jsPreview" + fileCount + "'>";
hideStuff += "</div>";
hideStuff += "<div class='col-sm-8'>";
hideStuff += "<button type='button' id='jsBtnUpload" + fileCount + "' class='btn btn-default'>";
hideStuff += "<i class='fa fa-plus'></i> {{ 'Pièce-jointe' | trans }}";
hideStuff += "</button>";
hideStuff += "</div>";
$("#filesBox").append("<div class='form-group'>" + hideStuff + newWidget + "</div>");
// On click => Simulate file behaviour
$("#jsBtnUpload" + fileCount).on('click', function(e){
$('#ticket_form_documents_' + fileCount + '_file').trigger('click');
});
// Once the file is added
$('#ticket_form_documents_' + fileCount + '_file').on('change', function() {
// Show its name
fileName = $(this).prop('files')[0].name;
$("#jsPreview" + fileCount).append(fileName);
// Hide the add file button
$("#jsBtnUpload" + fileCount).hide();
// Show the remove file button
$("#jsRemove" + fileCount).show();
// Create another instance of add file button and company
createAddFile(parseInt(fileCount)+1);
});
}
$(document).ready(function(){
createAddFile(fileCount);
fileCount++;
});
</script>
{% endblock %}
编辑:
与{{ doc.vars.value.name ?? '' }} 我没有错误了!!
但是,文件删除按钮仍然显示:
<div class="col col-xs-1" id="jsRemove1" style="">
<button type="button" class="btn btn-danger" onclick="removeFile($(this));"><i class="fa fa-times" aria-hidden="true"></i></button>
</div>
当文件类型不好时,如何让这些按钮消失?
正如已经提到的那样使用 All constraint
/**
* @Assert\All({
* @Assert\File(
* maxSize = "300k",
* mimeTypes = {"application/pdf", "application/x-pdf", "text/plain", "application/msword", "application/vnd.ms-excel", "image/jpeg", "image/x-citrix-jpeg", "image/png", "image/x-citrix-png", "image/x-png", "image/gif","application/zip"},
* mimeTypesMessage = "Liste des formats de fichiers acceptés : PDF, TXT, DOC, XLS, JPG, PNG, GIF"
* )
* })
*/
private $documents;
您还可以在 buildForm 方法中为您的 DocumentType 添加约束条件